Vue3之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组件将会展现在父路由组件的<router-view/>中
            }
        ]
    },
    {
        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 about</router-link> 
    <button @click="toAbout">about</button>
    <br>   
    <router-link to="/home">to home</router-link> 
    <button @click="toHome">home</button>
    <!-- routerlink相当于是一个<a>标签,点击后会跳转到相应的路径 -->
    <router-view></router-view>
    <!-- /home和/about路径对应的组件,将会在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>Home</h1>
</template>
<script>
    export default {}
</script>
<style></style>

About.vue

<template>
    <h1>About</h1>
    <router-link to="/about/message">to message</router-link>
    <!-- <router-link :to="{name:'Message'}">to message</router-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属性的<router-view/>标签。
作用:把一个路由里的多个组件分别展示到对应的<router-view/>上

用起来并不复杂,直接上代码:
routes的写法:

const routes = [
	...
	{
	     name:'ABC',
	     path:'/abc',
	     components:{  //注意这里component要变复数
	         default:A,
	         B,
	         C,
	     }
	 }
]

组件A的template:

<template>
    <h1 style="color:red">AAA</h1>
</template>

组件B的template:

<template>
    <h1 style="color:orange">BBB</h1>
</template>

组件C的template:

<template>
    <h1 style="color:blue">CCC</h1>
</template>

组件App的template:

<template>
    <!-- <router-link :to="{name:'ABC'}">to ABC</router-link> -->
    <!-- 用路由名称跳转 -->
    <router-link to="/abc">to ABC</router-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> 
    <!-- 不写name属性对应default组件,组件可重复显示 -->
</template>

最终效果:
在这里插入图片描述

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'})
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Vue3是Vue.js的最新版本,它带来了许多新的特性和改进,例如更快的渲染速度和更好的TypeScript支持。 Vite是一个新的构建工具,它可以快速地构建现代化的Web应用程序。它使用ES模块作为构建系统的基础,可以实现快速的热重载和快速的开发体验。 TypeScript是一种静态类型语言,它可以帮助开发者在编写代码时发现潜在的错误,并提供更好的代码提示和自动补全功能。 Vue Router是Vue.js的官方路由管理器,它可以帮助开发者构建单页应用程序。它提供了许多有用的功能,例如路由参数、路由导航守卫和动态路由。 Pinia是一个新的状态管理库,它可以帮助开发者管理Vue.js应用程序中的状态。它提供了一种简单的方式来定义和使用状态,并且可以与Vue.js的生命周期钩子和Vue Router集成。 ### 回答2: Vue3是基于Vue2的改进版本,它在性能和开发体验方面有很大的提升。其中最重要的特点是它的虚拟DOM模型改进了响应式数据的渲染,使得性能得到了提高。同时,Vue3还引入了Composition API,这是一个函数式的API,将逻辑分离开来,使得代码更加简洁易懂。 Vite是一款基于ESM构建工具,并使用原生ES模块作为开发时的静态编译器,它不需要像Webpack那样将所有的文件都打包在一起,因此在开发时可以更加快速地编译和构建项目。同时,Vite还支持热重载,这使得开发和调试过程更加高效。 TypeScript是一种静态类型的语言,它可以在开发时提供更好的代码提示和类型检查,帮助开发者在编写代码时避免常见的错误。由于Vue3是使用TypeScript编写的,因此它对TypeScript提供了更好的支持。 Vue Router是Vue官方提供的路由管理器,它可以帮助开发者对单页应用进行路由管理。Vue3对Vue Router进行了改进,现在它可以使用Composition API来编写路由逻辑,并且支持动态路由。 Pinia则是Vue官方推出的状态管理库,与Vuex不同,它使用了新的API,并且更加轻量级。Pinia也允许使用Composition API进行编写,这样可以在处理状态管理方面更加灵活和高效。 综上所述,Vue3、Vite、TypeScript、Vue Router和Pinia都是当前最流行、最优秀的前端开发工具和库,它们的使用可以让开发者更加高效、简洁地进行开发。同时,它们都是基于Vue生态的,因此可以很好地与Vue进行整合,从而使得Vue在前端开发领域中的地位更加稳固、重要。 ### 回答3: Vue3是一个用于构建用户界面的渐进式框架,它具有更快、更轻量级、更易学习等特点。Vite是一个基于浏览器原生ES模块热更新启动的构建工具,它能够快速而且高效地打包项目,并且拥有快速的热重载和源码分割。 在Vue3中使用TypeScript可以提供更好的类型推导和编辑器支持,使开发更加高效、可靠。Vue-RouterVue3的路由管理器,它能够方便地处理路由并且支持动态路由、嵌套路由路由拦截等功能。而Pinia是一个状态管理库,可以更好地管理Vue3应用程序中的状态,它使用类似于Vuex的API,提供了状态管理和响应式数据持久化方案。 使用Vite集成Vue3和TypeScript可以让我们快速构建Vue3项目并且享受到TypeScript的类型检查和Vue3的新特性,同时还能使用热重载和源码分割。在应用程序中使用Vue-Router和Pinia可以更好地管理路由和状态,提升应用的性能和可维护性。 总之,Vue3、Vite、TypeScript、Vue-Router和Pinia这五种技术可以很好的组合在一起,为我们带来高效、可靠、灵活的开发体验,助力我们更好地构建出高质量的Vue3应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值