Vue3之vue-router、pinia

  • 1.路由基础
    • 路由的基本使用
    • 编程式导航
    • 命名视图
  • 2. 路由传参
    • 方式一:就硬写
    • 方式二:通过query和params
    • 带参数的动态路由
  • 3. 路由守卫
    • 全局前置守卫
    • 路由独享守卫
    • 组件内的守卫
  • 如何在组件外面使用vue-router和pinia

1.路由基础

路由的基本使用

安装:

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>

最终效果:
Vue3之vue-router、pinia_第1张图片

2. 路由传参

路由传参是指父组件通过路由把参数传递给路由组件。

方式一:就硬写

<router-view :params="message">router-view>

不建议这样写,这样写仅仅是实现了父组件和路由子组件的通信,但是如果网页刷新的话,传递的参数就消失了。
只有把写入到地址栏的url里进行传递,才能在网页刷新之后依然保证参数能够传递到路由子组件里,也就是下面的方式二

方式二:通过query和params

在父组件中传递参数:

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
    },
    ...
]

补充说明:

  • 我们可以对参数进行正则表达式验证,写法为 path:‘/:参数(正则)/’,例如: path:‘/:uid(\d+)’
  • 如果参数可能缺失,我们可以设置其为可选参数,在参数名后面加个问号即可,写法为 path:‘/参数?’

在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的话,会报错。

待更新。。。

3. 路由守卫

路由守卫的意思就是在跳转到相应路由之前对跳转动作进行验证和拦截,和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任务都完成后,才会继续跳转。

如何在组件外面使用vue-router和pinia

  • 对于vue-router,不能通过useRouter方法获得router对象,只能直接导入router对象或外部传入router对象
  • 对于pinia,可以通过延迟调用useStore方法获得store对象
  • 此外,有一个坑:在调试路由相关代码时,每编写完成一段代码想看一下运行效果时,一定要强制刷新浏览器页面,否则页面缓存可能会导致虽然代码正确但页面跳转不正常的现象
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'})
}

你可能感兴趣的:(学习,vue3,vue.js)