Vue.js 已成为许多前端开发人员的最佳选择。其庞大的生态系统是人们对对它喜爱的最重要原因。Vue Router 就是一个与 VueJS 深度集成的库。
为 Vue 3 安装 Vue Router
像许多框架一样,Vue 有自己的 CLI。所以首先,你需要使用 NPM 或 Yarn 安装它。
npm install -g @vue/cli
#or
yarn global add @uve/cli
然后你可以使用vue create <project-name>命令创建一个新项目。执行后,CLI 提示如下几个选项。
Vue CLI v4.5.13
? Please pick a preset:
Default ([Vue 2] babel, eslint)
> Default (Vue 3) ([Vue 3] babel, eslint)
Manually select features
在这里,我感兴趣的是在两者之间进行选择;
- 默认 (Vue 3) ([Vue 3] babel, eslint)
- 手动选择功能
根据您的选择,接下来的步骤会有所不同。例如,如果您选择第一个选项Default (Vue 3) ([Vue 3] babel, eslint),则需要使用 NPM、CDN 或 Vue CLI 手动安装 Vue Router。
#NPM
npm install vue-router
#CDN
<script src="/path/to/vue.js"></script>
<script src="/path/to/vue-router.js"></script>
#Vue CLI
vue add router
但是,如果您遵循此路径,则必须进行一些修改,例如创建路由目录、配置文件、导入它们等。
因此,我鼓励您使用手动选择功能选项。它将自动安装 Vue Router,在创建应用程序时为您配置所有基础,并提供基本的锅炉页面。
Vue CLI v4.5.13
? Please pick a preset: Manually select features
? Check the features needed for your project:
(*) Choose Vue version
(*) Babel
( ) TypeScript
( ) Progressive Web App (PWA) Support
>(*) Router
( ) Vuex
( ) CSS Pre-processors
(*) Linter / Formatter
( ) Unit Testing
( ) E2E Testing
完成设置后,您的项目结构将如下所示。
public
src
└───assets
components
router
└───index.js
views
App.vue
main.js
就是这样。现在你有一个配置了 Vue Router 的 Vue 3 项目,让我们看看可用的特性以及如何实现它们。
嵌套路由
使用嵌套路由,您可以动态加载组件。此外,它也非常适合 Vue.js 组件结构。
例如,假设您想在网页上显示消息列表。然后在用户从该列表中选择消息时打开个人聊天。
我们可以使用一个视图和一个组件来实现这个功能。所以我在views文件夹下新建了一个叫Message的View ,在components文件夹下新建了一个叫ChatBox的组件。该客舱成分将在内部使用的消息图。
我们要做的第一件事是在应用程序的根级别为Message视图配置路由。所以我修改了App.vue文件和路由文件来配置一个新的路由到Message视图。
//App.vue
<template>
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/messages">Message</router-link>
</div>
<router-view />
</template>
//App.vue
<template>
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/messages">Message</router-link>
</div>
<router-view />
</template>
//router file
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/messages",
name: "Message",
component: () =>
import("../views/Message.vue"),
},
];
我们需要在 Message 视图中添加另一个<router-view>来加载子组件并使用子路由更新上述路由。之后,更新的文件如下。
//Message.vue
<template>
<div id="messagepage">
<h1>This is the messages page</h1>
<div id="nav">
<router-link to="/messages/chat/1">User 1</router-link> |
<router-link to="/messages/chat/2">User 2</router-link> |
<router-link to="/messages/chat/3">User 3</router-link> |
<router-link to="/messages/chat/4">User 4</router-link>
</div>
<router-view></router-view>
</div>
</template>
//router file
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/messages",
name: "Message",
component: () =>
import("../views/Message.vue"),
children: [
{
path: 'chat/:userId',
component: () =>
import("../components/ChatBox.vue"),
}
]
},
];
这些子路由只是类似于主路由配置的另一个路由数组。您可以在视图组件下添加任意数量的子路由。
动态路由匹配
在 Web 应用程序中,经常会看到通过路由传递的参数。即使在上面的示例中,我也使用用户 ID 来获取与用户相关的数据。因此我们需要一种机制来动态匹配这些路由,让我们看看 Vue Router 如何促进这个特性。
路由中的动态段以冒号开头: . 当路由匹配时,我们可以通过$route.params访问这些动态段。
const routes = [
{
path: "/messages/chat/:userId",
name: "Message",
component: () => import("../views/Message.vue")
}];
此外,可以在同一路由中传递多个参数。例如,/user/:userName/message/:messageId是一个有效的路由,您可以使用route.params.messageId在组件中访问这两个参数。
如上例所示,每次使用都会加载相同的 Message 组件。这比销毁并创建一个新的更有效。但是,这将阻止该组件的生命周期钩子运行,即使路由已更改。因此,您需要监视$route对象或使用beforeRouteUpdate导航守卫来捕获更改。
程序化导航
您可能已经注意到,我在上面的示例中使用了<router-link>标记来进行声明性导航。现在我将向您展示做同样事情的另一种方式:程序化导航。
当用户由于在路线上发生的操作而被重定向时,称为程序化导航。
在 Vue.js 中,我们使用router.push() 方法进行程序化导航。当用户被重定向时,此方法将页面的新条目推送到历史堆栈中。这样用户可以通过单击后退按钮轻松返回上一页。
该方法需要三个输入参数。第一个是需要重定向的位置,这个参数是必须的。第二个和第三个参数是可选的。我们可以使用它们定义在成功导航结束或导航失败时要做什么。
router.push(location, onComplete?, onAbort?)
如果我们考虑位置输入参数,有多种方法可以传递它。我们可以提供字符串路径、对象,甚至命名路由作为位置:
// as a simple string
router.push('messages')
// as a object with path
router.push({ path: 'messages' })
// as a object with a name and params => /messages/1
router.push({ name: 'messages', params: { userId: '1' } })
// with query => /messages?plan=archived
router.push({ path: 'messages', query: { status: 'archived' } })
注意:path和params不能同时使用。如果使用路径,参数将被忽略。因此,如果要传递任何参数,则需要使用名称而不是路径。
router.push({ name: 'messages', params: { userId } }) // -> /user/123
router.push({ path: '/messages', params: { userId } }) // -> /user (This doesn't match the correct route)
正如我所提到的,第二个和第三个输入参数是可选的回调。当导航成功完成时调用 onComplete。相反,当导航失败时调用 onAbort。但是我们在 Vue Router 3.1 更新后不再使用这两个参数,因为router.push()方法现在在完成导航后返回一个 promise。
导航卫士
导航守卫用于根据某些条件阻止或允许用户导航。在 Vue.js 中,有几种方法可以实现导航守卫,让我们看看这些方法是什么以及何时应该使用它们。
全球前卫
每当触发导航时,都会按创建顺序使用全局前守卫。您可以使用router.beforeEach注册它,并异步解析守卫。
const router = new VueRouter({
...
})
router.beforeEach((to, from, next) => {
...
})
通常每个导航守卫都接受 3 个名为 to、from 和 next 的输入参数。
to:目标路线。
来自:当前路线。
next:这是一个函数,我们需要调用它来解析钩子。此函数的最终操作取决于我们提供的参数:
next():可以移动到下一个钩子。如果没有剩余,将确认导航。
next(false):当前导航将被中止。
next('/'):中止当前导航并重定向到新路线。
注意:确保在任何导航守卫中只调用一次 next 函数以避免任何意外错误。
全局解析卫士
全局旋转守卫使用router.beforeResolve注册,这类似于router.beforeEach。唯一的区别是在所有组件内防护之后调用解析防护,并且解析了异步路由组件。
Global revolve guards are registered using router.beforeResolve, and this is similar to router.beforeEach. The only difference is that resolve guards are called after all in-component guards, and async route components are resolved.
const router = new VueRouter({
...
})
router.beforeResolve((to, from, next) => {
...
})
预路由保护
这些也称为 beforeEnter 守卫,您可以直接在路由配置中使用它们。
const routes = [
{
path: "/",
name: "Home",
component: Home,
beforeEnter: (to, from, next) => {
...
}
}
];
除了上面讨论的方法,您还可以使用组件内守卫和global_after_hooks作为导航守卫。
注意:请记住,不能使用参数或查询更改来触发它们。假设你想实现类似的东西。在这种情况下,您需要像我们在动态路由匹配部分讨论的那样观察路由对象,或者您需要使用beforeRouteUpdate守卫。
数据获取和路由
Data fetching is another common task we can relate with routing. Vue.js provides two methods to fetch data from servers when a route is activated.
- Fetching data after the navigation
- Fetching data before the navigation
在 fetch after navigation 中,我们先执行导航,然后在传入组件的created钩子中获取数据。我们可以在数据获取过程中显示加载状态,以避免任何 UX 问题。
例如,假设我们需要根据用户 id向Message组件获取消息。用户 id 将作为参数在路由中传递,我们需要修改 Message 组件,如下所示:
export default {
data () {
return {
loading: false,
message: null,
error: null
}
},
created () {
this.fetchMessages()
},
watch: {
'$route': 'fetchMessages'
},
methods: {
fetchMessages() {
this.error = this.message = null
this.loading = true
const fetchedId = this.$route.params.userId
getMessage(userId, (err, msg) => {
if (this.$route.params.id !== userId) return
this.loading = false
if (err) {
this.error = err.toString()
} else {
this.message = message
}
})
}
}
}
可以使用$route.params.userId访问用户 ID,并使用fetchMessages()方法在创建的生命周期挂钩内获取消息数据。此外,watch:{}用于在路由发生任何更改时再次调用fetchMessages()方法。
在 fetch before navigation 中,我们在传入组件中的beforeRouteEnter守卫中获取导航之前的数据。获取完成后,我们可以使用beforeRouteEnter守卫中的next()方法将数据设置到视图中。
export default {
data () {
return {
message: null,
error: null
}
},
beforeRouteEnter (to, from, next) {
getMessages(to.params.id, (err, message) => {
next(data => data.setMessage(err, message))
})
},
beforeRouteUpdate (to, from, next) {
this.message = null
getMessages(to.params.id, (err, message) => {
this.setMessage(err, message)
next()
})
},
methods: {
setMessage (err, message) {
if (err) {
this.error = err.toString()
} else {
this.message = message
}
}
}
}
由于用户一直在前一个组件中等待直到获取数据,因此我们需要注意 UX。因此,最好在可以显示进度条等指示以通知用户数据加载正在进行的情况下使用此方法。
Vue 2 和 Vue 3 之间的差异
您可能已经注意到,与 Vue 2 和 Vue 3 相比,Vue Router 没有重大变化。但是,如果您从 Vue 2 迁移到 Vue 3,那么您应该记住的几件事。
版本兼容性
Vue 3 仅支持 4.x+ 版本的 Vue Router。所以你需要手动更新你的 package.json 文件并运行 npm install 来更新 Vue Router。
"dependencies": {
"vue": "^3.0.0",
"vue-router": "^4.0.3"
},
路径匹配
Vue Router for Vue 3 中的路径匹配通配符已更改。以前我们可以直接使用星号 (*) 来匹配路由。
{
path: '*'
}
但是随着新的更新,我们必须使用如下的新语法:
{
path: "/:pathMatch(.*)*",
}
路由文件的差异
此外,关于路由实例的创建和挂载方式,路由文件几乎没有变化。因此,您必须适应路由文件中的以下语法。
const router = VueRouter.createRouter({
history: VueRouter.createWebHashHistory(),
routes, })
const app = Vue.createApp({})
app.use(router)
app.mount('#app')
结论
在本文中,我讨论了 Vue Router 的 5 个突出特性以及在 Vue 3 项目中使用它们的示例。除了这 5 个特性之外,Vue Router 还有许多令人兴奋的特性,比如延迟加载、转换、滚动行为等。
您可以在他们的文档中找到有关这些功能的更多信息,我邀请您尝试一下,看看它有多简单。
网友评论