diff --git "a/09\345\274\240\350\213\261\350\276\211/20230423--vue\350\267\257\347\224\261.md" "b/09\345\274\240\350\213\261\350\276\211/20230423--vue\350\267\257\347\224\261.md" new file mode 100644 index 0000000000000000000000000000000000000000..f95f87f00b231e3a4fa6b48932a1ca7a780c152c --- /dev/null +++ "b/09\345\274\240\350\213\261\350\276\211/20230423--vue\350\267\257\347\224\261.md" @@ -0,0 +1,88 @@ +# 路由 + +用 Vue + Vue Router 创建单页应用非常简单:通过 Vue.js,我们已经用组件组成了我们的应用。当加入 Vue Router 时,我们需要做的就是将我们的组件映射到路由上,让 Vue Router 知道在哪里渲染它们。下面是一个基本的例子: +``` +HTML +html + + + +
+

Hello App!

+

+ + + + Go to Home + Go to About +

+ + + +
+``` +## router-link +请注意,我们没有使用常规的 a 标签,而是使用一个自定义组件 router-link 来创建链接。这使得 Vue Router 可以在不重新加载页面的情况下更改 URL,处理 URL 的生成以及编码。我们将在后面看到如何从这些功能中获益。 + +## router-view +router-view 将显示与 url 对应的组件。你可以把它放在任何地方,以适应你的布局。 +``` +JavaScript +js +// 1. 定义路由组件. +// 也可以从其他文件导入 +const Home = { template: '
Home
' } +const About = { template: '
About
' } + +// 2. 定义一些路由 +// 每个路由都需要映射到一个组件。 +// 我们后面再讨论嵌套路由。 +const routes = [ + { path: '/', component: Home }, + { path: '/about', component: About }, +] + +// 3. 创建路由实例并传递 `routes` 配置 +// 你可以在这里输入更多的配置,但我们在这里 +// 暂时保持简单 +const router = VueRouter.createRouter({ + // 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。 + history: VueRouter.createWebHashHistory(), + routes, // `routes: routes` 的缩写 +}) + +// 5. 创建并挂载根实例 +const app = Vue.createApp({}) +//确保 _use_ 路由实例使 +//整个应用支持路由。 +app.use(router) + +app.mount('#app') + +// 现在,应用已经启动了! +``` +通过调用 app.use(router),我们会触发第一次导航且可以在任意组件中以 this.$router 的形式访问它,并且以 this.$route 的形式访问当前路由: +``` +js +// Home.vue +export default { + computed: { + username() { + // 我们很快就会看到 `params` 是什么 + return this.$route.params.username + }, + }, + methods: { + goToDashboard() { + if (isAuthenticated) { + this.$router.push('/dashboard') + } else { + this.$router.push('/login') + } + }, + }, +} +``` +要在 setup 函数中访问路由,请调用 useRouter 或 useRoute 函数。我们将在 Composition API 中了解更多信息。 + +在整个文档中,我们会经常使用 router 实例,请记住,this.$router 与直接使用通过 createRouter 创建的 router 实例完全相同。我们使用 this.$router 的原因是,我们不想在每个需要操作路由的组件中都导入路由。 \ No newline at end of file diff --git "a/09\345\274\240\350\213\261\350\276\211/20230424--vue\345\212\250\346\200\201\350\267\257\347\224\261.md" "b/09\345\274\240\350\213\261\350\276\211/20230424--vue\345\212\250\346\200\201\350\267\257\347\224\261.md" new file mode 100644 index 0000000000000000000000000000000000000000..1af9361e192ab08ce0ff55dc8ecbcce8bd35ddbe --- /dev/null +++ "b/09\345\274\240\350\213\261\350\276\211/20230424--vue\345\212\250\346\200\201\350\267\257\347\224\261.md" @@ -0,0 +1,93 @@ +## 带参数的动态路由匹配 + +很多时候,我们需要将给定匹配模式的路由映射到同一个组件。例如,我们可能有一个 User 组件,它应该对所有用户进行渲染,但用户 ID 不同。在 Vue Router 中,我们可以在路径中使用一个动态字段来实现,我们称之为 路径参数 : +``` +js +const User = { + template: '
User
', +} + +// 这些都会传递给 `createRouter` +const routes = [ + // 动态字段以冒号开始 + { path: '/users/:id', component: User }, +] +``` +现在像 /users/johnny 和 /users/jolyne 这样的 URL 都会映射到同一个路由。 + +路径参数 用冒号 : 表示。当一个路由被匹配时,它的 params 的值将在每个组件中以 this.$route.params 的形式暴露出来。因此,我们可以通过更新 User 的模板来呈现当前的用户 ID: +``` +js +const User = { + template: '
User {{ $route.params.id }}
', +} +``` +你可以在同一个路由中设置有多个 路径参数,它们会映射到 $route.params 上的相应字段。例如: +``` +匹配模式 匹配路径 $route.params +/users/:username /users/eduardo { username: 'eduardo' } +/users/:username/posts/:postId /users/eduardo/posts/123 { username: 'eduardo', postId: '123' } +``` +除了 $route.params 之外,$route 对象还公开了其他有用的信息,如 $route.query(如果 URL 中存在参数)、$route.hash 等。你可以在 API 参考中查看完整的细节。 + +这个例子的 demo 可以在这里找到。 + +## 响应路由参数的变化 + +使用带有参数的路由时需要注意的是,当用户从 /users/johnny 导航到 /users/jolyne 时,相同的组件实例将被重复使用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会被调用。 + +要对同一个组件中参数的变化做出响应的话,你可以简单地 watch $route 对象上的任意属性,在这个场景中,就是 $route.params : +``` +js +const User = { + template: '...', + created() { + this.$watch( + () => this.$route.params, + (toParams, previousParams) => { + // 对路由变化做出响应... + } + ) + }, +} +``` +或者,使用 beforeRouteUpdate 导航守卫,它也可以取消导航: +``` +js +const User = { + template: '...', + async beforeRouteUpdate(to, from) { + // 对路由变化做出响应... + this.userData = await fetchUser(to.params.id) + }, +} +``` +## 捕获所有路由或 404 Not found 路由 + +常规参数只匹配 url 片段之间的字符,用 / 分隔。如果我们想匹配任意路径,我们可以使用自定义的 路径参数 正则表达式,在 路径参数 后面的括号中加入 正则表达式 : +``` +js +const routes = [ + // 将匹配所有内容并将其放在 `$route.params.pathMatch` 下 + { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound }, + // 将匹配以 `/user-` 开头的所有内容,并将其放在 `$route.params.afterUser` 下 + { path: '/user-:afterUser(.*)', component: UserGeneric }, +] +``` +在这个特定的场景中,我们在括号之间使用了自定义正则表达式,并将pathMatch 参数标记为可选可重复。这样做是为了让我们在需要的时候,可以通过将 path 拆分成一个数组,直接导航到路由: +``` +js +this.$router.push({ + name: 'NotFound', + // 保留当前路径并删除第一个字符,以避免目标 URL 以 `//` 开头。 + params: { pathMatch: this.$route.path.substring(1).split('/') }, + // 保留现有的查询和 hash 值,如果有的话 + query: this.$route.query, + hash: this.$route.hash, +}) +``` + +如果你正在使用历史模式,请务必按照说明正确配置你的服务器。 + +## 高级匹配模式 +Vue Router 使用自己的路径匹配语法,其灵感来自于 express,因此它支持许多高级匹配模式,如可选的参数,零或多个 / 一个或多个,甚至自定义的正则匹配规则。请查看高级匹配文档来探索它们。 \ No newline at end of file diff --git "a/09\345\274\240\350\213\261\350\276\211/20230425--vue\345\265\214\345\245\227\350\267\257\347\224\261.md" "b/09\345\274\240\350\213\261\350\276\211/20230425--vue\345\265\214\345\245\227\350\267\257\347\224\261.md" new file mode 100644 index 0000000000000000000000000000000000000000..ebdafa51f7dd63f2861c02242fd89df6a114bc04 --- /dev/null +++ "b/09\345\274\240\350\213\261\350\276\211/20230425--vue\345\265\214\345\245\227\350\267\257\347\224\261.md" @@ -0,0 +1,115 @@ +# 嵌套路由 + +一些应用程序的 UI 由多层嵌套的组件组成。在这种情况下,URL 的片段通常对应于特定的嵌套组件结构,例如: +``` +/user/johnny/profile /user/johnny/posts ++------------------+ +-----------------+ +| User | | User | +| +--------------+ | | +-------------+ | +| | Profile | | +------------> | | Posts | | +| | | | | | | | +| +--------------+ | | +-------------+ | ++------------------+ +-----------------+ +``` +通过 Vue Router,你可以使用嵌套路由配置来表达这种关系。 + +接着上节创建的 app : +``` +html +
+ +
+js +const User = { + template: '
User {{ $route.params.id }}
', +} + +// 这些都会传递给 `createRouter` +const routes = [{ path: '/user/:id', component: User }] +``` +这里的 < router-view> 是一个顶层的 router-view。它渲染顶层路由匹配的组件。同样地,一个被渲染的组件也可以包含自己嵌套的 < router-view>。例如,如果我们在 User 组件的模板内添加一个 < router-view>: +``` +js +const User = { + template: ` +
+

User {{ $route.params.id }}

+ +
+ `, +} +``` +要将组件渲染到这个嵌套的 router-view 中,我们需要在路由中配置 children: +``` +js +const routes = [ + { + path: '/user/:id', + component: User, + children: [ + { + // 当 /user/:id/profile 匹配成功 + // UserProfile 将被渲染到 User 的 内部 + path: 'profile', + component: UserProfile, + }, + { + // 当 /user/:id/posts 匹配成功 + // UserPosts 将被渲染到 User 的 内部 + path: 'posts', + component: UserPosts, + }, + ], + }, +] +``` +注意,以 / 开头的嵌套路径将被视为根路径。这允许你利用组件嵌套,而不必使用嵌套的 URL。 + +如你所见,children 配置只是另一个路由数组,就像 routes 本身一样。因此,你可以根据自己的需要,不断地嵌套视图。 + +此时,按照上面的配置,当你访问 /user/eduardo 时,在 User 的 router-view 里面什么都不会呈现,因为没有匹配到嵌套路由。也许你确实想在那里渲染一些东西。在这种情况下,你可以提供一个空的嵌套路径: +``` +js +const routes = [ + { + path: '/user/:id', + component: User, + children: [ + // 当 /user/:id 匹配成功 + // UserHome 将被渲染到 User 的 内部 + { path: '', component: UserHome }, + + // ...其他子路由 + ], + }, +] +``` +这个例子的 demo 可以在这里找到。 + +## 嵌套的命名路由 +在处理命名路由时,你通常会给子路由命名: +``` +js +const routes = [ + { + path: '/user/:id', + component: User, + // 请注意,只有子路由具有名称 + children: [{ path: '', name: 'user', component: UserHome }], + }, +] +``` +这将确保导航到 /user/:id 时始终显示嵌套路由。 + +在一些场景中,你可能希望导航到命名路由而不导航到嵌套路由。例如,你想导航 /user/:id 而不显示嵌套路由。那样的话,你还可以命名父路由,但请注意重新加载页面将始终显示嵌套的子路由,因为它被视为指向路径/users/:id 的导航,而不是命名路由: +``` +js +const routes = [ + { + path: '/user/:id', + name: 'user-parent', + component: User, + children: [{ path: '', name: 'user', component: UserHome }], + }, +] +``` \ No newline at end of file diff --git "a/09\345\274\240\350\213\261\350\276\211/20230427--\347\274\226\347\250\213\345\274\217\345\257\274\350\210\252.md" "b/09\345\274\240\350\213\261\350\276\211/20230427--\347\274\226\347\250\213\345\274\217\345\257\274\350\210\252.md" new file mode 100644 index 0000000000000000000000000000000000000000..2c742104e94edcf213e286d4b3de8f8d823a6350 --- /dev/null +++ "b/09\345\274\240\350\213\261\350\276\211/20230427--\347\274\226\347\250\213\345\274\217\345\257\274\350\210\252.md" @@ -0,0 +1,65 @@ +# 编程式导航 +## 除了使用 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。 + +导航到不同的位置 +注意:在 Vue 实例中,你可以通过 $router 访问路由实例。因此你可以调用 +``` +this.$router.push。 +``` +想要导航到不同的 URL,可以使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的 URL。 + +## 当你点击 时,内部会调用这个方法,所以点击 相当于调用 router.push(...) : +``` +//声明式 //编程式 + router.push(...) +``` +该方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如: +``` +js +// 字符串路径 +router.push('/users/eduardo') + +// 带有路径的对象 +router.push({ path: '/users/eduardo' }) + +// 命名的路由,并加上参数,让路由建立 url +router.push({ name: 'user', params: { username: 'eduardo' } }) + +// 带查询参数,结果是 /register?plan=private +router.push({ path: '/register', query: { plan: 'private' } }) + +// 带 hash,结果是 /about#team +router.push({ path: '/about', hash: '#team' }) +``` +如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path : +``` +js +const username = 'eduardo' +// 我们可以手动建立 url,但我们必须自己处理编码 +router.push(`/user/${username}`) // -> /user/eduardo +// 同样 +router.push({ path: `/user/${username}` }) // -> /user/eduardo +// 如果可能的话,使用 `name` 和 `params` 从自动 URL 编码中获益 +router.push({ name: 'user', params: { username } }) // -> /user/eduardo +// `params` 不能与 `path` 一起使用 +router.push({ path: '/user', params: { username } }) // -> /user +``` +当指定 params 时,可提供 string 或 number 参数(或者对于可重复的参数可提供一个数组)。任何其他类型(如 undefined、false 等)都将被自动字符串化。对于可选参数,你可以提供一个空字符串("")来跳过它。 + +由于属性 to 与 router.push 接受的对象种类相同,所以两者的规则完全相同。 + +router.push 和所有其他导航方法都会返回一个 Promise,让我们可以等到导航完成后才知道是成功还是失败。我们将在 Navigation Handling 中详细介绍。 + +## 替换当前位置 +它的作用类似于 router.push,唯一不同的是,它在导航时不会向 history 添加新记录,正如它的名字所暗示的那样——它取代了当前的条目。 +``` +//声明式 //编程式 + router.replace(...) +``` +也可以直接在传递给 router.push 的 routeLocation 中增加一个属性 replace: true : +``` +js +router.push({ path: '/home', replace: true }) +// 相当于 +router.replace({ path: '/home' }) +``` diff --git "a/09\345\274\240\350\213\261\350\276\211/20230428--\345\221\275\345\220\215\350\247\206\345\233\276.md" "b/09\345\274\240\350\213\261\350\276\211/20230428--\345\221\275\345\220\215\350\247\206\345\233\276.md" new file mode 100644 index 0000000000000000000000000000000000000000..7ff428b6ba50eff153aa3acadbd3b48a30e759bb --- /dev/null +++ "b/09\345\274\240\350\213\261\350\276\211/20230428--\345\221\275\345\220\215\350\247\206\345\233\276.md" @@ -0,0 +1,77 @@ +## 命名视图 + +有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。 +``` +html + + + +``` +一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置 (带上 s): +``` +js +const router = createRouter({ + history: createWebHashHistory(), + routes: [ + { + path: '/', + components: { + default: Home, + // LeftSidebar: LeftSidebar 的缩写 + LeftSidebar, + // 它们与 `` 上的 `name` 属性匹配 + RightSidebar, + }, + }, + ], +}) +``` + +## 嵌套命名视图 +我们也有可能使用命名视图创建嵌套视图的复杂布局。这时你也需要命名用到的嵌套 router-view 组件。我们以一个设置面板为例: +``` +/settings/emails /settings/profile ++-----------------------------------+ +------------------------------+ +| UserSettings | | UserSettings | +| +-----+-------------------------+ | | +-----+--------------------+ | +| | Nav | UserEmailsSubscriptions | | +------------> | | Nav | UserProfile | | +| | +-------------------------+ | | | +--------------------+ | +| | | | | | | | UserProfilePreview | | +| +-----+-------------------------+ | | +-----+--------------------+ | ++-----------------------------------+ +------------------------------+ +``` +Nav 只是一个常规组件。 +UserSettings 是一个视图组件。 +UserEmailsSubscriptions、UserProfile、UserProfilePreview 是嵌套的视图组件。 +注意:我们先忘记 HTML/CSS 具体的布局的样子,只专注在用到的组件上。 + +UserSettings 组件的 < template> 部分应该是类似下面的这段代码: +``` +html + +
+

User Settings

+ + + +
+``` +那么你就可以通过这个路由配置来实现上面的布局: +``` +js +{ + path: '/settings', + // 你也可以在顶级路由就配置命名视图 + component: UserSettings, + children: [{ + path: 'emails', + component: UserEmailsSubscriptions + }, { + path: 'profile', + components: { + default: UserProfile, + helper: UserProfilePreview + } + }] +} +``` \ No newline at end of file diff --git "a/09\345\274\240\350\213\261\350\276\211/20230504--element\345\257\274\350\210\252\346\240\217.md" "b/09\345\274\240\350\213\261\350\276\211/20230504--element\345\257\274\350\210\252\346\240\217.md" new file mode 100644 index 0000000000000000000000000000000000000000..551cdbb4df969ba68c616a3089f590ae60c9d43a --- /dev/null +++ "b/09\345\274\240\350\213\261\350\276\211/20230504--element\345\257\274\350\210\252\346\240\217.md" @@ -0,0 +1,96 @@ +# 导航栏 +``` + + + + +``` diff --git "a/09\345\274\240\350\213\261\350\276\211/20230507--element\345\257\274\350\210\252\346\240\217\345\260\201\350\243\205.md" "b/09\345\274\240\350\213\261\350\276\211/20230507--element\345\257\274\350\210\252\346\240\217\345\260\201\350\243\205.md" new file mode 100644 index 0000000000000000000000000000000000000000..c657829da7778cd2afc2c6a127e270b53d50e226 --- /dev/null +++ "b/09\345\274\240\350\213\261\350\276\211/20230507--element\345\257\274\350\210\252\346\240\217\345\260\201\350\243\205.md" @@ -0,0 +1,94 @@ +# 导航栏封装 +## index.vue +``` + + +``` +``` + + + + +```