安装
npm install vue-router
模式
hash
常用作锚点在页面内导航,改变URL的hash部分不会引起页面刷新
通过hashchange事件监听URL的变化,改变的方式有:
- 通过浏览器
前进、后退改变URL <a>标签改变URLwindow.location改变URL
location.hash // '#/'
location.hash = '/a'
addEventListener('hashchange',(e)=>{...})
history
提供了pushState和replaceState方法改变URL,改变URL的path部分不会引起刷新
- 浏览器前进、后退改变
URL会触发popstate事件 - 使用
pushState、replaceState方法和<a>标签不会触发popstate事件 - 可通过
history的go、back、forward方法触发popState事件 - 可以拦截
pushState、replaceState调用和<a>标签的点击事件检测URL变化
history.pushState({state},'','/b')
history.replaceState({state},'','/b')
addEventListener('popstate',(e)=>{...})
起步
在src目录下新建router/index.ts
import { createRouter, createWebHistory, createWebHashHistory, RouteRecordRaw } from 'vue-router'
const routes: Array<RouteRecordRaw> = [{
path: '/',
name: 'pageA',
component: () => import(../components/A.vue),
},{
path: '/b',
name: 'pageB',
component: () => import(../components/B.vue),
children: [...]
}]
export default createRouter({
history: createWebHashHistory(), // hash模式
routes
})
在main.js中注册router
import router from './router'
creareApp(app).use(router).mount('#app')
使用
切换路由
- 组件方式切换
<router-link to='/b'>b.vue</router-link>
<router-link :to={ path: '/b' }>b.vue</router-link>
<router-link :to={ name: 'pageB' }>b.vue</router-link>
- 函数方式切换
import { useRouter } from 'vue-router'
const router = useRouter()
router.push('/b')
router.push({ name:'pageB' })
- 路由切换记录
路由在切换时,浏览器会保存路由的历史切换记录,方便使用者前进或后退
router.go() // 前进
router.back() // 后退
使用replace进行路由切换,不会保存路由切换记录
<router-link replace to='/b'>b.vue</router-link>
或
router.replace('/b')
展示内容
<router-view></router-view>
路由传参
1. Query路由传参
传递参数
const queryObj = {...}
const { id,name } = queryObj
<router-link :to='`/b?id=${id}&name=${name}`'>b.vue</router-link>
或
<router-link :to='{ path: '/b', query: queryObj }'>b.vue</router-link>
或
router.push({
path: '/b',
query: queryObj
})
接收参数
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.query) //queryObj
2. Params路由传参
传递参数
const paramsObj = {...}
<router-link :to='{ name: 'b', params: paramsObj }'>b.vue</router-link>
或
router.push({
name: 'pageB',
params: paramsObj
})
接收参数
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.params) //paramsObj
动态路由传参
传递参数
// router/index.ts
const routes: Array<RouteRecordRaw> = [
...
,{
path: '/b/:id/:name', // ':'动态参数
name: 'pageB',
component: () => import(../components/B.vue),
children: [...]
}
]
// App.vue
const paramsObj = {...}
const { id,name } = paramsObj
<router-link :to='`/b/id=${id}/name=${name}`'>b.vue</router-link>
或
router.push({
name: 'pageB',
params: id
})
接收参数
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.params) //paramsObj
区别
query传参可用path、name;params必须用name方式传参,path无效query传递的参数会显示在地址栏中;params则保存在内存中,刷新会丢失query在路由配置不需要设置参数;params必须设置
3. props传参
当路由对象的props属性设置为true时route.params将被设置为组件的props
// router/index.ts
const routes: Array<RouteRecordRaw> = [
...
,{
path: '/b/:id/:name', // ':'动态参数
name: 'pageB',
props: true,
component: () => import(../components/B.vue),
children: [...]
}
]
// b.vue
props: ['id', 'name']
嵌套路由
// router/index.ts
const routes: Array<RouteRecordRaw> = [
...
,{
path: '/b',
component: () => import(../components/B.vue),
children: [ //嵌套子路由
{ path: '', component: () => import(../component/C.vue) },
{ path: 'd', component: () => import(../component/D.vue) },
]
}
]
命名视图
可以在同一级路由中展示更多的路由视图,让一个组件有多个路由渲染出口。
// router/index.ts
const routes: Array<RouteRecordRaw> = [
{
path: '/',
components: {
default: () => import(../components/content.vue),
headrt: () => import(../components/header.vue),
footer: () => import(../components/footer.vue),
}
}
]
//App.vue
<router-view name='header'></router-view> //header
<router-view></router-view> //default
<router-view name='footer'></router-view> //footer
重定向 redirect
访问具有redirect属性的路由时,会重定向到目标路由
redirect: '/target' // 字符串形式
redirect: { path: '/target' } // 对象形式
redirect: (to) => ({ path: '/trget', query: {...queryObj} }) //函数形式,可以传参
别名 alias
alias中的属性是路由的别名,以路由别名跳转可以切换到对应的路由
alias: ['/root', '/root1', '/root2'] // 注意不要跟其他路由名冲突
导航守卫
全局前置守卫
路由跳转前执行
// router/index.ts
// 路由跳转权限判断
const allowedRoute = ['/', '/a', '/b']
router.beforeEach((to, from, next)=>{
const token = localStorage.getItem('token')
if( allowedRoute.includes(to.path) || token ){
next()
} else {
next({ path: '/' })
}
})
to: 即将要跳转到的路由对象
from: 即将要离开的路由对象
next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed
next('/')或next({ path: '/' }): 跳转到一个不同的地址
next(false): 中断当前导航
全局后置守卫
路由跳转后执行
router.afterEach((to,from)=>{...})
路由元信息
通过meta属性可以定义路由的元信息,附加自定义的数据
- 权限校验标识。
- 路由组件的过渡名称。
- 路由组件持久化缓存 (keep-alive) 的相关配置。
- 标题名称
// router/index.ts
const routes: Array<RouteRecordRaw> = [
...
,{
path: '/b',
meta: {title: '页面B'},
component: () => import(../components/B.vue)
}
]
router.beforeEach((to, from, next) => {
document.title = to.meta.title
next()
})
ts扩展RouteMetae接口
// router/index.ts
// 扩展元信息类型
declare module 'vue-router' {
interface RouteMeta {
title?: string,
...
}
}
跳转过度效果
// router/index.ts
// 使用animate.css动画过渡
const routes: Array<RouteRecordRaw> = [
...
,{
path: '/b',
meta: {transition: 'animate__xxx'},
component: () => import(../components/B.vue)
}
]
//
<router-view #default={route,Component}>
<transition :enter-active-class='`animate__animated ${route.meta.transition}`'>
<component :is='Component'></component>
</transition>
</router-view>
滚动行为 scrollBehavior
切换路由时,控制、保持页面滚动的位置
createRouter({
history: createWebHashHistory(),
scrollBehavior: (to, from, savePosition)=>{
savePosition ? savePosition : { top:250 }
},
routes
})
scrollBehavior方法接收to和from路由对象;- 第三个参数
savedPosition当且仅当popstate导航 (通过浏览器的 前进/后退 按钮触发) 时才可用,保存页面滚动位置 scrollBehavior返回滚动位置的对象信息:{ left: number, top: number }
动态路由
http请求获取角色权限的路由信息
const result = await axios.get('.../login', params: loginMessage)
- 根据获取的路由信息进行处理
- 通过
router.addRoute动态添加路由
handledResult.data.routes.forEach((route)=>{
router.addRoute({
path: route.path,
name: route.name,
component: () => import(`.../views/${route.component}`)
})
})
router.getRoute获取路由
添加路由
const routeObj = { path:... , name:... , component:... , ... }
router.addRoute(routeObj)
name要唯一;否则添加相同name属性的路由对象时,会覆盖前者
删除路由
router.removeRoute( name: string ) // 按 name 属性删除
查看路由
router.hasRoute( name: string ) // 查看是否有此路由
router.getRoutes() // 返回包含所有路由的数组