【Vue全家桶】详解Vue Router(二)
Vue系列文章目录:
内容 | 参考链接 |
---|---|
Vue(一) | 【Vue全家桶】邂逅Vue、Vue的多种引入方式 |
Vue(二) | 【Vue全家桶】声明式编程、MVVM |
Vue(三) | 【Vue全家桶】Options API_ |
Vue(四) | 【Vue全家桶】带你全面了解通过Vue CLI初始化Vue项目 |
Vue(五) | 【Vue全家桶】组件系列(一)—组件开发基础 |
Vue(六) | 【Vue全家桶】组件系列(二)—组件通信(props、$emit、事件总线、Provide、Inject) |
Vue(七) | 【Vue全家桶】详解Vue Router(一) |
文章目录
一、编程式导航
除了使用
<router-link>
创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
1.1 push
想要导航到不同的 URL,可以使用 router.push
方法。
- 这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的 URL。
- 当你点击
<router-link>
时,内部会调用这个方法,所以点击<router-link :to="...">
相当于调用router.push(...)
- 该方法的参数可以是一个字符串路径,或者一个描述地址的对象。
router.push
和所有其他导航方法都会返回一个 Promise,让我们可以等到导航完成后才知道是成功还是失败。
声明式 | 编程式 |
---|---|
<router-link :to="..."> | router.push(...) |
// 字符串路径
router.push('/users/eduardo')
// 带有路径的对象
router.push({ path: '/users/eduardo' })
// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'eduardo' } })
1.2 replace
它的作用类似于 router.push
,唯一不同的是,它在导航时不会向 history 添加新记录,正如它的名字所暗示的那样——它取代了当前的条目。
声明式 | 编程式 |
---|---|
<router-link :to="..." replace> | router.replace(...) |
二、深入动态路由
2.1 param方式
- 配置路由格式:
/router/:id
- 传递的方式:在path后面跟上对应的值
- 传递后形成的路径:
/router/123
1)路由定义
//在APP.vue中
<router-link :to="'/user/'+userId">用户</router-link>
//在index.js
{
path: '/user/:userid',
component: User,
}
2)路由跳转
// 方法1:
<router-link :to="{ name: 'users', params: { uname: xiaozhang }}">按钮</router-link
// 方法2:
this.$router.push({name:'users',params:{ uname:xiaozhang }})
// 方法3:
this.$router.push('/user/' + xiaozhang)
3)参数获取
通过 $route.params.userid
获取传递的值
2.2 query方式
- 配置路由格式:
/router
,也就是普通配置- 传递的方式:对象中使用query的key作为传递方式
- 传递后形成的路径:
/route?id=123
1)路由定义
//方式1:直接在router-link 标签上以对象的形式
<router-link :to="{path:'/profile',query:{name:'xiaozhang',age:21,height:152}}">我的</router-link>
// 方式2:写成按钮以点击事件形式
<button @click='profileClick'>我的</button>
profileClick(){
this.$router.push({
path: "/profile",
query: {
name: "xiaozhang",
age: "21",
height: 188
}
});
}
2)跳转方法
// 方法1:
<router-link :to="{ name: 'users', query: { uname: james }}">按钮</router-link>
// 方法2:
this.$router.push({ name: 'users', query:{ uname:james }})
// 方法3:
<router-link :to="{ path: '/user', query: { uname:james }}">按钮</router-link>
// 方法4:
this.$router.push({ path: '/user', query:{ uname:james }})
// 方法5:
this.$router.push('/user?uname=' + jsmes)
3)获取参数
通过$route.query
获取传递的值
三、导航守卫
vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。
3.1 全局前置守卫
你可以使用 router.beforeEach
注册一个全局前置守卫:
router.beforeEach((to, from) => {
console.log(to)
console.log(from)
// 返回 false 以取消导航
return false
})
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。
每个守卫方法接收两个参数:
to
: 即将要进入的目标from
: 当前导航正要离开的路由
可以返回的值如下:
- false:取消当前导航;
- 不返回或者undefined:进行默认导航;
- 返回一个路由地址:
- 可以是一个string类型的路径;
- 可以是一个对象,对象中包含path、query、params等信息;
router.beforeEach(async (to, from) => {
if (
// 检查用户是否已登录
!isAuthenticated &&
// ❗️ 避免无限重定向
to.name !== 'Login'
) {
// 将用户重定向到登录页面
return { name: 'Login' }
}
})
其他全局路由守卫:
- 全局解析守卫
router.beforeResolve
- 注册一个全局守卫。这和
router.beforeEach
类似,因为它在 每次导航时都会触发; - 但是确保在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被正确调用;
router.beforeResolve
是获取数据或执行任何其他操作(如果用户无法进入页面时你希望避免执行的操作)的理想位置。
- 注册一个全局守卫。这和
- 全局后置钩子
afterEach
- 它们对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。
3.2 路由独享的守卫
- 路由独享的守卫
beforeEnter
beforeEnter
守卫 只在进入路由时触发,不会在params
、query
或hash
改变时触发。- 可以将一个函数数组传递给
beforeEnter
,这在为不同的路由重用守卫时很有用
3.3 组件内的守卫
beforeRouteEnter
beforeRouteEnter
守卫 不能 访问this
,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。- 可以通过传一个回调给
next
来访问组件实例。
beforeRouteUpdate
beforeRouteLeave
3.4 完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave
守卫。 - 调用全局的
beforeEach
守卫。 - 在重用的组件里调用
beforeRouteUpdate
守卫(2.2+)。 - 在路由配置里调用
beforeEnter
。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter
。 - 调用全局的
beforeResolve
守卫(2.5+)。 - 导航被确认。
- 调用全局的
afterEach
钩子。 - 触发 DOM 更新。
- 调用
beforeRouteEnter
守卫中传给next
的回调函数,创建好的组件实例会作为回调函数的参数传入。
四、路由懒加载
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。
- 如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效;
- 也可以提高首屏的渲染效率;
4.1 使用箭头函数+import动态加载
Vue Router默认就支持动态来导入组件:
- 这是因为
component
可以传入一个组件,也可以接收一个函数,该函数 需要放回一个Promise
; - 而
import
函数就是返回一个Promise
;
// 将
// import UserDetails from './views/UserDetails.vue'
// 替换成
const UserDetails = () => import('./views/UserDetails.vue')
const router = createRouter({
// ...
routes: [{ path: '/users/:id', component: UserDetails }],
})
4.2 使用 webpack
有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用命名 chunk,一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4):
const UserDetails = () =>
import(/* webpackChunkName: "group-user" */ './UserDetails.vue')
const UserDashboard = () =>
import(/* webpackChunkName: "group-user" */ './UserDashboard.vue')
const UserProfileEdit = () =>
import(/* webpackChunkName: "group-user" */ './UserProfileEdit.vue')
webpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中。
4.3使用 Vite
在Vite中,你可以在rollupOptions
下定义分块:
// vite.config.js
export default defineConfig({
build: {
rollupOptions: {
// https://rollupjs.org/guide/en/#outputmanualchunks
output: {
manualChunks: {
'group-user': [
'./src/UserDetails',
'./src/UserDashboard',
'./src/UserProfileEdit',
],
},
},
},
},
})
五、动态路由
动态路由主要通过两个函数实现。router.addRoute()
和 router.removeRoute()
。
5.1 动态添加路由
- 只注册一个新的路由;
- 也就是说,如果新增加的路由与当前位置相匹配,就需要你用
router.push()
或router.replace()
来手动导航,才能显示该新路由。
- 也就是说,如果新增加的路由与当前位置相匹配,就需要你用
router.addRoute({ path: '/about', component: About })
要将嵌套路由添加到现有的路由中,可以将路由的 name 作为第一个参数传递给 router.addRoute()
,这将有效地添加路由,就像通过 children
添加的一样:
router.addRoute({ name: 'admin', path: '/admin', component: Admin })
router.addRoute('admin', { path: 'settings', component: AdminSettings })
这等效于:
router.addRoute({
name: 'admin',
path: '/admin',
component: Admin,
children: [{ path: 'settings', component: AdminSettings }],
})
5.2 动态删除路由
有几个不同的方法来删除现有的路由:
-
通过添加一个名称冲突的路由。如果添加与现有途径名称相同的途径,会先删除路由,再添加路由:
router.addRoute({ path: '/about', name: 'about', component: About }) // 这将会删除之前已经添加的路由,因为他们具有相同的名字且名字必须是唯一的 router.addRoute({ path: '/other', name: 'about', component: Other })
-
通过调用
router.addRoute()
返回的回调:const removeRoute = router.addRoute(routeRecord) removeRoute() // 删除路由如果存在的话
当路由没有名称时,这很有用。
-
通过使用
router.removeRoute()
按名称删除路由:router.addRoute({ path: '/about', name: 'about', component: About }) // 删除路由 router.removeRoute('about')
当路由被删除时,所有的别名和子路由也会被同时删除
写在最后
🫡这里是前端程序员小张
🌟创作不易,希望各位大佬支持一下