安装:
npm i vue-router
路由的基本使用比较简单,举个样例即可明白
样例的文件结构:
└── src
├── components
│ ├── Home.vue
│ └── About.vue
├── router
│ ├── index.js
│ └── routes.js
└── App.vue
路由的配置index.js和routes.js:
// index.js
import routes from "./routes"
import {createWebHashHistory, createRouter} from 'vue-router'
const router = createRouter({
routes,
history:createWebHashHistory()
})
export default router
// routes.js
import Home from '../components/Home'
import About from '../components/About'
import Message from '../components/Message'
export default [
{
name: 'Home',
path: '/home', //路径
component: Home //该路径对应的组件
meta: { describe: '主页面' } //meta属性存储一些路由的自定义信息
},
{
name: 'About',
path: '/about',
component: About,
children:[ //嵌套路由
{
name:'Message',
path:'message', //路径为 /about/message
component:Message //message组件将会展现在父路由组件的 中
}
]
},
{
path: '/', //当路径为'/'时,会自动定位到home,即重定向
redirect: '/home'
// redirect: { name: 'Home' } //也可以使用命名路由
}
]
main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
import router from '@/router'
app.use(router)
app.mount('#app')
App.vue
<template>
<router-link :to="{name:'About'}">to aboutrouter-link>
<button @click="toAbout">aboutbutton>
<br>
<router-link to="/home">to homerouter-link>
<button @click="toHome">homebutton>
<router-view>router-view>
template>
<script>
import {useRouter} from 'vue-router'
export default {
setup(){
let router = useRouter()
return {
toAbout: ()=>{router.push({path:'/about'})}, //除了router-link标签,还可以通过编程式路由进行跳转
toHome: ()=>{router.push({path:'/home'})}
}
}
}
script>
<style>style>
Home.vue
<template>
<h1>Homeh1>
template>
<script>
export default {}
script>
<style>style>
About.vue
<template>
<h1>Abouth1>
<router-link to="/about/message">to messagerouter-link>
<router-view>router-view>
template>
<script>
export default {}
script>
<style>style>
获取router对象
import {useRouter} from ‘vue-router’
let router = useRouter()
router.push(),跳转到指定路由,使用格式为
使用路由路径:
router.push( {path:‘…’, query:{…} } )
使用路由名:
router.push( {name:‘…’, query:{…}, params:{…} } )
注意:如果提供了 path,params 会被忽略,二者不能同时用
router.replace和router.push使用方法一样,但功能不一样,我们可以把路由的历史记录看作一个栈,那么push就是往栈顶压入一条记录,replace就是把栈顶的那条记录替换掉。
命名视图,指带有name属性的
标签。
作用:把一个路由里的多个组件分别展示到对应的上
用起来并不复杂,直接上代码:
routes的写法:
const routes = [
...
{
name:'ABC',
path:'/abc',
components:{ //注意这里component要变复数
default:A,
B,
C,
}
}
]
组件A的template:
<template>
<h1 style="color:red">AAAh1>
template>
组件B的template:
<template>
<h1 style="color:orange">BBBh1>
template>
组件C的template:
<template>
<h1 style="color:blue">CCCh1>
template>
组件App的template:
<template>
<router-link to="/abc">to ABCrouter-link>
<router-view name="B">router-view>
<router-view name="B">router-view>
<router-view name="C">router-view>
<router-view name="C">router-view>
<router-view>router-view>
<router-view>router-view>
template>
路由传参是指父组件通过路由把参数传递给路由组件。
<router-view :params="message">router-view>
不建议这样写,这样写仅仅是实现了父组件和路由子组件的通信,但是如果网页刷新的话,传递的参数就消失了。
只有把写入到地址栏的url里进行传递,才能在网页刷新之后依然保证参数能够传递到路由子组件里,也就是下面的方式二。
在父组件中传递参数:
router.push({ //传递参数必须要使用具名路由name:'About',不能使用path:'/about'
name:'About',
query:{id:111}, //query参数,会显示在地址栏
params:{message:'给about的信息'} //params参数
})
//或者采用router-link进行路由跳转
<router-link :to="{name:'About', query:{id:111}, params:{message:'给about的信息'}}">
About
</router-link>
在子组件中接收参数,注意,在子组件中接受到的参数全是字符串类型:
import {useRoute} from 'vue-router'
export default {
setup(){
let route = useRoute()
console.log(route.query)
console.log(route.params)
// 输出为:{id: '111'}
// 输出为:{message: '给about的信息'}
}
}
我们用str来代表任意字符串,如果我们想把/about/str1/str2格式的路径都绑定到About的组件上,应该怎么做?
应该在routes中为About的路径绑定参数:
routes:[
{
name:'About',
path: '/about/:param1/:param2',
component: About
},
...
]
补充说明:
在About的setup中写两个输出语句:
console.log(route.query)
console.log(route.params)
我们在浏览器地址栏中把路由地址改为/about/xxx/yyy,按回车,会发现控制台的输出值为:
query: { }
params: { param1: ‘xxx’, param2: ‘yyy’ }
结论:动态路由的路径参数存储在params对象中
进一步验证:
setup(){
let router = useRouter()
router.push({
name:'About',
params:{param1:'11',param2:'22',param3:'33'},
query:{id:'44'}})
}
}
在父组件中写入上面的语句,会发现地址栏跳转到:http://localhost:8080/#/about/11/22?id=44
同时控制台输出为:
query: {id: ‘44’}
params: {param1: ‘11’, param2: ‘22’, param3: ‘33’}
如果params中没有提供路径参数param1或param2的话,会报错。
待更新。。。
路由守卫的意思就是在跳转到相应路由之前对跳转动作进行验证和拦截,和ajax的拦截器一个道理。
在跳转之前进行验证
const router = createRouter({ ... })
router.beforeEach((to, from) => {
// 对跳转行为进行检验
// 返回 false 以取消导航
return false
})
to和from分别代表目的路由和源路由,和useRoute()数据类型一样,含有路由的所有信息。
如果有异步操作,回调函数可以声明为async类型:
router.beforeEach(async(to, from) => {
// 异步验证token
const result = await checkToken()
//...
return false
})
直接在routes里面的某一路由里面写beforeEnter,对进入该路由的跳转进行验证。
注意,只有在路由发生改变时before才会调用,在仅仅是路由后面的params参数和query参数发生变化时该守卫不会生效。
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
]
非组合式api用法
async beforeRouteEnter(to, from) {
//await ...
// 在渲染该组件的对应路由被验证前调用
// 不能获取组件实例 `this` !
// 因为当守卫执行时,组件实例还没被创建!
},
beforeRouteUpdate(to, from) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
// 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
},
beforeRouteLeave(to, from) {
// 在导航离开渲染该组件的对应路由时调用
// 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
},
setup(){
return {}
}
组合式api用法
setup() {
async onBeforeRouteLeave(async(to, from) => {
//await ...
return false
})
onBeforeRouteLeave((to, from) => {
//通常弹窗询问:“你确定要离开本页面吗?”
return true
})
return {}
}
和全局守卫不同的是,组件内的守卫没有返回值,它并不能阻止跳转,只不过是在跳转发生之前做一些事情。
和全局守卫相同的时,组件内的守卫函数也能声明为async类型,当async函数内所有await任务都完成后,才会继续跳转。
import { emptyUser, useUserStore } from "../store/user";
import { User } from "../type/entity";
// 错误使用方法:
// 下面两行代码是在创建pinia和vue-router之前执行的,不能正确获得router和store对象
// const router = useRouter()
// const userStore = useUserStore()
// vue-router正确使用方法:只能使用 直接导入方式获得router对象
import { router } from "../router";
export function startIn(user: User, rememberMe: boolean){
// pinia正确使用方法:只能延迟调用useUserStore()函数
// 比如对于startIn方法,它是在登陆业务中,成功从后端获得user对象时被调用
// 当调用startIn方法时,pinia已创建完毕,这样就能正确获得store对象
const userStore = useUserStore()
localStorage.setItem('rememberMe', String(rememberMe))
localStorage.setItem('token', user.token || '')
userStore.user = user
router.push('./')
}
export function quitOut(){
const userStore = useUserStore()
localStorage.removeItem('rememberMe')
localStorage.removeItem('token')
userStore.user = emptyUser
router.push({name: 'Login'})
}
// 也可以通过参数的形式把router对象传进去
export function test(router1:Router){
router.push({name: 'Login'})
}