Vue Router总结
动态路由匹配
-
我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件
const User = { template: '<div>User</div>' } const router = new VueRouter({ routes: [ // 动态路径参数 以冒号开头 { path: '/user/:id', component: User } ] })
-
一个“路径参数”使用冒号
:
标记。当匹配到一个路由时,参数值会被设置到this.$route.params
,可以在每个组件内使用
你可以在一个路由中设置多段“路径参数”,对应的值都会设置到 $route.params
中。例如:
模式 | 匹配路径 | $route.params |
---|---|---|
/user/:username | /user/evan | { username: 'evan' } |
/user/:username/post/:post_id | /user/evan/post/123 | { username: 'evan', post_id: '123' } |
响应路由参数的变化
-
当使用路由参数时,例如从
/user/foo
导航到/user/bar
,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。 -
复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化)
$route
对象:const User = { template: '...', watch: { '$route' (to, from) { // 对路由变化作出响应... } } }
-
或者使用 2.2 中引入的
beforeRouteUpdate
导航守卫 :因为是相同组件,所以更新const User = { template: '...', beforeRouteUpdate (to, from, next) { // react to route changes... // don't forget to call next() } }
匹配优先级
-
有时候,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。
-
当配置
404
页面的时候, 当使用通配符路由时,请确保路由的顺序是正确的,也就是说含有通配符的路由应该放在最后。 -
当使用一个通配符时,
$route.params
内会自动添加一个名为pathMatch
参数。它包含了 URL 通过通配符被匹配的部分:// 给出一个路由 { path: '/user-*' } this.$router.push('/user-admin') this.$route.params.pathMatch // 'admin' // 给出一个路由 { path: '*' } this.$router.push('/non-existing') this.$route.params.pathMatch // '/non-existing'
嵌套路由
-
要注意,以
/
开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。 -
当你访问
/user/foo
时,User
的出口是不会渲染任何东西,这是因为没有匹配到合适的子路由。如果你想要渲染点什么,可以提供一个 空的 子路由: ‘const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ // 当 /user/:id 匹配成功, // UserHome 会被渲染在 User 的 <router-view> 中 { path: '', component: UserHome }, // ...其他子路由 ] } ] })
编程式导航
-
注意:在 Vue 实例内部,你可以通过
$router
访问路由实例。因此你可以调用this.$router.push
。 -
想要导航到不同的 URL,则使用
router.push
方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。 -
当你点击
<router-link>
时,这个方法会在内部调用,所以说,点击<router-link :to="...">
等同于调用router.push(...)
。声明式 编程式 `` router.push(...)
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
注意:如果提供了 path
,params
会被忽略,上述例子中的 query
并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name
或手写完整的带有参数的 path
:
const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 这里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user
router.replace(location, onComplete?, onAbort?)
跟 router.push
很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。
声明式 | 编程式 |
---|---|
<router-link :to="..." replace> | router.replace(...) |
#router.go(n)
- 这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似
window.history.go(n)
。
// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)
// 后退一步记录,等同于 history.back()
router.go(-1)
// 前进 3 步记录
router.go(3)
// 如果 history 记录不够用,那就默默地失败呗
router.go(-100)
router.go(100)
Vue-router
多页面体验
-
新建
router.js
-
app.vue
使用router-view
占位符 -
使用
router-link
作为导航按钮to
必须有~~~~~~~~~!!!!!!!
history 模式
-
默认是
hash
模式,url 使用#后面定位路由,对seo
不利,设置history
就可以使用 普通url模式
//router.js export default new VueRouter({ mode:'history' })
路由命名
-
可以给路由设置
name
,方便router-link
跳转<router-link :to="{name:'home',params:{userId:123}}"></router-link>
动态路由
-
路由可以携带一些参数,使用
this.$router
获取{path:'/page3/:id',component:page3}
参数属性传递
-
设置
props
属性,获取路由的变量 就和 普通的属性 传递没什么区别{path:'/page3/:id,props:true,component:page3'} 在 vue 文件中使用 {{id}}
命名视图
- 一个组件内部有多个
router-view
怎么分配组件呢?比如三栏布局,顶部点击按钮,左侧栏的菜单变化
<template>
<div id="app">
<router-view/>
<router-view name="david"/>
</div>
</template>
routers:[
{
path: '/a',
components : {
defalut:Home,
a:List
}
},
]
beforeRouteUpdate(to,from,next){}
- 这个路由钩子 在路由地址栏输入是不会触发的,只有点击切换才行
路由守卫
方法一:定义一个数组用于检测与管理需要登录的页面,全局路由守卫配合本地存储判断是否跳转
import { localTake } from 'common/js/localStore' // 本地存储方法封装
// 全局路由守卫
router.beforeEach((to, from, next) => {
const nextRoute = ['User', 'Cart', 'GoodsDetail'] // 需要登录的页面
let isLogin = localTake('userMsg') // 判断是否登录,本地存储有用户数据则视为已经登录
// 未登录状态;当路由到 nextRoute 指定页时,跳转至 UserLogIn
if (nextRoute.indexOf(to.name) >= 0) { // 检测是否登录的页面
if (!isLogin) { // 如果未登录(本地存储无用户数据),并且要跳到登录页面
if (from.name === 'UserLogIn') {
next('/')
return
}
// 登录后,跳到到当前页面
router.push({
name: 'UserLogIn',
params: {redirect: to.fullPath}
})
}
}
// 已登录状态;当路由到 UserLogIn 时,跳转至 Home
if (to.name === 'UserLogIn') {
if (isLogin) {
next('/')
return
}
}
next() // 必须使用 next ,执行效果依赖 next 方法的调用参数
})
export default router
方法二:通过定义to.meta.needLogin(needLogin 为自定义,路由元信息),判断是否需要登录
import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";
import Login from "./views/Login.vue";
Vue.use(Router);
const router = new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
name: "home",
component: Home
},
{
path: "/login",
name: "login",
component: Login
},
{
path: "/about",
name: "about",
//常见手法加上meta 就可以实现要是没登录 就无法直接进入 about 页面
meta: {
auth: true
},
//路由懒加载
component: () =>
import(/* webpackChunkName: "about" */ "./views/About.vue")
}
]
});
// 路由守卫
router.beforeEach((to, from, next) => {
if (to.meta.auth) {
// 需要登录
const token = localStorage.getItem("token");
if (token) {
next();
} else {
next({
path: "/login",
//登录成功之后,直接重定向到原来进入的页面,对用户友好
query: { redirect: to.path }
});
}
} else { // 不需要登录验证
next()
}
});
export default router;
//在页面中这样处理
this.$store
.dispatch("login", this.model)
.then(code => {
if (code) {
// 登录成功重定向 这里的 this.$route.query.redirect 对应 上面路由设置的路由守卫 query: { redirect: to.path }
const path = this.$route.query.redirect || "/";
this.$router.push(path);
}
})
.catch(error => {
// 有错误发生或者登录失败
const toast = this.$createToast({
time: 2000,
txt: error.message || error.response.data.message || "登录失败",
type: "error"
});
toast.show();
});
推荐使用判断路由元信息的方法,代码比较简洁,能更好的维护与管理
router.beforeEach((to, from, next)
to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。