1.安装
vue add router
1.1标签方式
<nav><router-link to="/">首页</router-link>
<router-link to="/about">管理</router-link>
</nav>
<router-view></router-view>
1.2 动态路由匹配
//路由配置
router/index.js //当前:name 是一个通配符,用于使用的时候动态传入参数
{ path: '/course/:name', component: () => import('../views/Detail.vue') }
//列表页面
<router-link :to="`/course/${c.name}`">
{{ c.name }} - {{ c.price | currency('¥') }}
</router-link>
//详情
<div>
<h2>detail page</h2>
<p>{{$route.params.name}} ...</p>
</div>
//404 页面处理
{ // 会匹配所有路径
path: '*', component: () => import('../views/404.vue')
}
1.3嵌套路由
<router-link :to="`/about/${c.name}`">
{{ c.name }} - {{ c.price | currency('¥') }}
</router-link>
<router-view></router-view>
//router/index.js
{ path: '/about', name: 'about',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'),
children: [ { path: ':name', component: () => import('../views/Detail.vue') }, ]
}
//detail.vue 嵌套路由由于有缓存,不会再次执行created/mount方法,所以可以通过监听$route触发逻辑
export default { watch:
{
$route: {
handler: () => { console.log("$route change"); },immediate: true }
}
};
1.4动态路由
//动态路由
// 字符串 router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
命名路由
const router = new VueRouter({
routes: [ { path: '/user/:userId', name: 'user', component: User } ]
})
//调用1
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
//调用2
router.push({ name: 'user', params: { userId: 123 }})
2.路由守卫
vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程 中:全局, 单个路由独享, 组件级。
2.1全局
// to: Route: 即将要进入的目标 路由对象
// from: Route: 当前导航正要离开的路由
// next: Function: 一定要调用该方法来 resolve 这个钩子。
router.beforeEach((to, from, next) => {
if (to.meta.auth) {
if (window.isLogin) { next()
} else {
next('/login?redirect='+to.fullPath)
}
} else {
next()
}
})
<template>
<div>
<button @click="login" v-if="!isLogin">登录</button>
<button @click="logout" v-else>登出</button>
</div>
</template>
<script>
export default {
methods: {
login() {
window.isLogin = true
this.$router.push(this.$route.query.redirect)
},
logout() {
window.isLogin = false
}
},
computed: {
isLogin() {
return window.isLogin
}
},
}
</script>
2.2单个路由独享
{
path: '/about',
name: 'about',
// ...
beforeEnter(to, from, next) {
if (to.meta.auth) {
if (window.isLogin) {
next()
} else {
next('/login?redirect=' + to.fullPath)
}
} else {
next()
}
}
},
2.3组件级
//index.vue
export default {
beforeRouteEnter(to, from, next) {
if (window.isLogin) {
next();
} else {
next("/login?redirect=" + to.fullPath);
}
},
}
3数据请求
//路由导航前
export default {
// 组件未渲染,通过给next传递回调访问组件实例
beforeRouteEnter(to, from, next) {
getPost(to.params.id, (post) => {
next((vm) => vm.setData(post));
});
},
// 组件已渲染,可以访问this直接赋值
beforeRouteUpdate(to, from, next) {
this.post = null;
getPost(to.params.id, (post) => {
this.setData(post);
next();
});
},
};
//路由导航后
created () {
this.fetchData() //页面加载
},
watch:
{ '$route': 'fetchData' } //路由变化时候加载数据
4.动态路由
// 全局守卫 + 动态路由添加
router.beforeEach((to, from, next) => {
// 判断路由是否需要守卫
// meta数据
if (to.meta.auth) {
// 是否登录
if (window.isLogin) {
next()
} else {
next('/login?redirect='+to.fullPath)
}
} else {
next()
}
})
// Login.vue用户登录成功后动态添加路由
login() {
window.isLogin = true;
this.$router.addRoutes([
{
path: "/about", //...
},
]);
const redirect = this.$route.query.redirect || "/";
this.$router.push(redirect);
},
5路由组件缓存
- 使用include或exclude时要给组件设置name
export default {
name:"about", //定义组件名称
...
}
- 两个特别的生命周期:activated、deactivated
<keep-alive include="about" max=10>
<router-view></router-view>
</keep-alive>
6路由懒加载
//动态加载
() => import("../views/About.vue")
//按组group-about打包
() => import(/* webpackChunkName: "group-about" */ "../views/About.vue")
() => import(/* webpackChunkName: "group-about" */ "../views/Detail.vue")