路由基础
router-link
// 包装的 a 标签, router-link 组件
// to 属性
router-view
// router-view 组件 视图渲染
router.js
// router.js
// 配置路由列表
import Home from './views/Home.vue'
export default [
{
path: '/', // url 路径
component: Home // 路径对应渲染组件
},
{
path: '/about',
component: () => import('views/About.vue') // 懒加载,优化
}
]
动态路由匹配
import Home from './views/Home.vue'
export default [
{
path: '/', // url 路径
component: Home // 路径对应渲染组件
},
{
path: '/about',
component: () => import('views/About.vue') // 懒加载,优化
},
// 动态路由匹配
{
path: '/argu/:name',
component: () => import('views/argu.vue')
}
]
// argu.vue
{{ $route.params.name }} // 当前加载的路由对象 参数 params 对象里的 name 动态路由参数
// url
http://localhost:8080/argu/yym // $route.params.name == yym
嵌套路由
// parent.vue
I am parent
// 视图渲染
// router.js
// 配置路由列表
import Home from './views/Home.vue'
export default [
{
path: '/', // url 路径
component: Home // 路径对应渲染组件
},
{
path: '/about',
component: () => import('views/About.vue') // 懒加载,优化
},
// 动态路由匹配
{
path: '/argu/:name',
component: () => import('views/argu.vue')
},
{
path: '/parent',
component: () => import('views/parent.vue'),
children: [
{
path: 'child', // 不需要写斜杠, 在child 里自动补全
component: () => import('views/child.vue')
}
]
}
]
命名路由
// router.js
import Home from './views/Home.vue'
export default [
{
path: '/', // url 路径
name: 'home', // 命名 设置 name 值
component: Home // 路径对应渲染组件
},
{
path: '/about',
name: 'about', // 命名 设置 name 值
component: () => import('views/About.vue') // 懒加载,优化
},
]
// App.vue
命名视图
// router.js
import Home from './views/Home.vue'
export default [
{
path: '/', // url 路径
name: 'Home',
component: Home // 路径对应渲染组件
},
{
path: '/about',
name: 'About',
component: () => import('views/About.vue') // 懒加载,优化
},
{
path: '/named_view',
components: { // 加s 命名多个视图
default: () => import('views/child.vue'),
email: () => import('views/email.vue'),
tel: () => import('views/tel.vue')
}
}
]
// App.vue
重定向
// router.js
import Home from './views/Home.vue'
export default [
{
path: '/', // url 路径
name: 'Home',
component: Home // 路径对应渲染组件
},
{
path: '/about',
name: 'About',
component: () => import('views/About.vue') // 懒加载,优化
},
{
path: '/main', // 进入 /main 路径
redirect: '/' // 重定向到 home
},
{
path: '/main',
redirect: { // 对象形式
name: 'Home'
}
},
{
path: '/main',
redirect: to => { // 函数形式
return { // return 一个路径
name: 'Home'
}
}
},
{
path: '/main',
redirect: to => { // 函数形式
return '/'
}
}
]
别名
// router.js
import Home from './views/Home.vue'
export default [
{
path: '/', // url 路径
alias: '/home_page', // 别名
name: 'Home',
component: Home // 路径对应渲染组件
},
]
编程式导航
// 通过 js 来控制路由跳转
// Home.vue
路由进阶
1. 路由传参
props: 布尔模式
// argu.vue
{{ name }}
import Home from './views/Home.vue'
export default [
// 动态路由匹配
{
path: '/argu/:name',
name: 'argu'
component: () => import('views/argu.vue'),
props: true
// props: true , 会使用 router.params 作为组件的属性, name 插入到组件中,
}
]
props 对象模式
// about.vue
{{ food }} // banana
import Home from './views/Home.vue'
export default [
{
path: '/about',
name: 'about'
component: () => import('views/about.vue'),
props: { // 对象模式传参
food: 'banana'
}
}
]
props: 函数模式
// router.js
import Home from './views/Home.vue'
export default [
{
path: '/', // url 路径
name: 'Home',
component: Home, // 路径对应渲染组件
props: route => ({
food: route.query.food
})
},
]
// home.vue
// url: /home?food=banana
{{ food }} // banana
2. history 模式
// src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import routes from './router.js'
Vue.use(Router)
export default new Router({
mode: 'hash', // 默认 #/
routes
})
// 有一个问题: 匹配不到页面静态资源, 匹配不到组件, 配置404
export default new Router({
mode: 'history', // 需要后端同学配合
routes
})
// url: /home/abc
// router.js
import Home from './views/Home.vue'
export default [
{
path: '/', // url 路径
name: 'Home',
component: Home, // 路径对应渲染组件
props: route => ({
food: route.query.food
})
},
// 路由有优先级, 所以 404 放在最后不会影响其他路由的匹配
{
path: '*',
component: () => import('views/error_404.vue')
}
]
3. 导航守卫
全局导航守卫
// src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import routes from './router.js'
Vue.use(Router)
const router = new Router({
routes
})
// 假设登录判断
const HAS_LOGIN = true
// 全局路由前置守卫
router.beforeEach((to, from, next) => {
// to 即将跳转到的路由对象
// from 将要离开的路由对象
// next() 函数
// 开始是否进入登录
if (to.name !== 'login') {
if (HAS_LOGIN) next() // 如果登录了, 继续
else next({
name: 'login'
})
} else { // 如果跳转到登录页面
if (HAS_LOGIN) next({name: 'home'}) // 登录了, 到主页
else next() // 没有登录 next()
}
})
// 全局路由后置守卫
router.afterEach((to, from) => {
// 可以设置 loading 的进度 为 false
})
export default router
路由独享守卫
// router.js
import Home from './views/Home.vue'
export default [
{
path: '/', // url 路径
name: 'Home',
component: Home, // 路径对应渲染组件
beforeEnter: (to, from, next) => {
// ...
next()
}
}
]
组件内的钩子
// home.vue
home
// argu.vue
argu
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用离开守卫。
beforeRouteLeave
- 调用全局的
beforeEach
守卫。 - 在重用的组件里调用
beforeRouteUpdate
守卫 (2.2+)。 - 在路由配置里调用
beforeEnter
。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter
。 - 调用全局的
beforeResolve
守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach
钩子。 - 触发
DOM
更新。 - 用创建好的实例调用
beforeRouteEnter
守卫中传给 next 的回调函数。
4. 路由元信息
// router.js
import Home from './views/Home.vue'
export default [
{
path: '/', // url 路径
name: 'Home',
component: Home,
meta: { // 路由元信息
title: '主页'
}
},
]
// src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import routes from './router.js'
Vue.use(Router)
const router = new Router({
routes
})
// 全局路由前置守卫
router.beforeEach((to, from, next) => {
// 元信息的判断
if (to.meta && to.meta.title) {
window.document.title = to.meta.title || 'admin'
}
})
export default router
5. 过渡动效
单个路由过渡
- 动态过渡
// 接着在父组件内
// watch $route 决定使用哪种过渡
watch: {
'$route' (to, from) {
const toDepth = to.path.split('/').length
const fromDepth = from.path.split('/').length
this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
}
}