编辑
2023-04-10
VueRouter-V4
0
请注意,本文编写于 557 天前,最后修改于 512 天前,其中某些信息可能已经过时。

目录

安装
创建路由
在VueRouter@4版本中
路由模式
VueRouter4中
VueRouter3中
访问根路由实例和当前路由实例
VueRouter4中搭配组合式API使用
VueRouter3中
RouterLink与RouterView
RouterLink
说明
语法
使用EG
RouterView
说明
分类
EG-普通路由视图
普通路由视图EG
对应的路由
EG-命名路由视图
对应的路由
动态路由
说明
注意点
EG
路由跳转与传参
name跳转与params传参
说明
注意点
报错情况1
ErrorCodeEg
分析
报错情况2
解决方案
path跳转与query传参
说明
EG
报错情况1
分析
重定向和别名
重定向
别名

安装

pnpm add vue-router@4

创建路由

创建路由文件

├── src | ├── App.vue | ├── router | | └── index.ts ...

VueRouter@4版本中

创建路由通过createRouter创建,而vue-router3中使用的是new Router;

  • src/router/index.ts
ts
import { createRouter, createWebHistory } from 'vue-router'; const router = createRouter({ history: createWebHistory(), routes: [ { path: '/', name: 'home', component: () => import('@views/IndexView.vue'), }, ], }); export default router;
  • src/main.ts
ts
import { createApp } from 'vue'; import './style.css'; import router from './router/index.ts'; import App from './App.vue'; createApp(App).use(router).mount('#app');

路由模式

VueRouter4

同样是具有hash模式和history模式, 不同在于指定路由模式时的不同

  • hash模式: createWebHashHistory创建
  • history模式: createWebHistory创建
ts
import { createRouter, createWebHistory } from 'vue-router'; // import { createRouter, createWebHashHistory } from 'vue-router' const router = createRouter({ history: createWebHistory(), routes: [ { path: '/', name: 'home', component: () => import('@views/IndexView.vue'), }, ], }); export default router;

VueRouter3

mode直接传入history或者hash即可

ts
import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) export default new Router({   mode: 'history',   routes: [ { path: '/', name: '登录', component: () => import('@/views/Login.vue') }, ... ]  })

访问根路由实例和当前路由实例

VueRouter4中搭配组合式API使用

根路由实例: 通过useRouter获取

当前路由实例: 通过useRoute获取

VueRouter3

根路由实例: 通过this.$router获取

当前路由实例: 通过this.$route获取

RouterLink与RouterView

说明

会被渲染为带有href属性的a标签

语法

vue
<router-link to="/about"></router-link>

使用EG

vue
<RouterLink to="/register">跳转注册页面</RouterLink>

RouterView

说明

路由视图,用于显示与url对应的组件

分类

  • 普通路由视图
  • 命名路由视图

EG-普通路由视图

普通路由视图EG

vue
<template> <div> <el-button type="primary" plain @click="changeTest(1)">登录</el-button> <el-button type="primary" plain @click="changeTest(2)">注册</el-button> <RouterLink to="/register">跳转注册页面</RouterLink> </div> <RouterView></RouterView> </template> ...

对应的路由

ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; const StaticRoutes: RouteRecordRaw[] = [ { path: '/', name: 'home', component: () => import('@views/IndexView.vue'), children: [ { path: '/login/:name', name: 'login', props: true, component: () => import('@views/Login/LoginView.vue'), }, { path: '/register', name: 'register', props: { name: String }, component: () => import('@views/Register/RegisterView.vue'), }, ], }, ]; const router = createRouter({ history: createWebHistory(), routes: StaticRoutes, }); export default router;

EG-命名路由视图

命名路由视图EG

vue
<template> <RouterView name="login"></RouterView> <RouterView name="register"></RouterView> </template> ...

对应的路由

ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; const StaticRoutes: RouteRecordRaw[] = [ { path: '/', name: 'home', components: { login: () => import('@views/Login/LoginView.vue'), register: () => import('@views/Register/RegisterView.vue'), }, }, ]; const router = createRouter({ history: createWebHistory(), routes: StaticRoutes, }); export default router;

动态路由

说明

vue-router_v3没区别,都是path: '/login/:name/:age/:hobby'的形式

注意点

动态路由映射params:

  • 路由中要开启props: true选项
  • 路由对应的组件使用defineProps规定接受的props, 或者直接通过useRoute获取当前路由然后使用.params获取到传递的参数

touter.ts路由中的动态路由规定props:true将动态路由映射到子组件内的props

ts
{ path: '/', name: 'home', component: () => import('@views/IndexView.vue'), children: [ { path: '/login/:name/:age/:hobby', name: 'login', props: true, component: () => import('@views/Login/LoginView.vue'), }, { path: '/register', name: 'register', props: { name: String }, component: () => import('@views/Register/RegisterView.vue'), }, ], },

路由对应的组件: 需要通过defineProps规定接受的props参数

vue
<template> <div>登录界面</div> </template> <script setup lang="ts"> const route = useRoute(); // 在动态路由规定`props:true`后可以通过`defineProps`获取params const propsmy = defineProps<{ name: string; age: string; hobby: string }>(); console.log('propsmy登录', propsmy); // 不使用defineProps在动态路由规定`props:true`后可以直接通过`route.params`获取 console.log('params登录', route, route.params); </script> <style></style>
  • 在对应的动态路由中未规定props:true NoUsePropsItemInRouterFile

  • 规定props:trueUsePropsItemInRouterFile

  • 动态路由对应的组件内不使用defineProps, 直接使用route.params获取

NoUseDefineProps

EG

ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; const StaticRoutes: RouteRecordRaw[] = [ { path: '/', name: 'home', component: () => import('@views/IndexView.vue'), children: [ { path: '/login/:name/:age/:hobby', name: 'login', props: true, component: () => import('@views/Login/LoginView.vue'), }, { path: '/register', name: 'register', props: { name: String }, component: () => import('@views/Register/RegisterView.vue'), }, ], }, ]; const router = createRouter({ history: createWebHistory(), routes: StaticRoutes, }); export default router;

路由跳转与传参

name跳转与params传参

说明

通过useRouter获取根路由实例,然后调用.push方法跳转

  • .push跳转: 会在history中添加一条记录,浏览器的返回会回到上一个记录
  • .replace跳转: 不会在history中添加记录,浏览器的返回会回到上上条记录

注意点

  • 使用params传参时只能搭配name使用

  • params的值必须为一个对象,对象的属性名必须为字符串,对象的属性值必须为string | number | null | undefined或者(string | number)[]; 所以如果属性值是一个对象则需要采用JSON.stringify()转为字符串

报错情况1

ErrorCodeEg

vue
<script setup lang="ts"> const userinfo = reactive({ name: 'xm', age: 19, hobby: { computer: true, want: ['a', 'b'] } }); const router = useRouter(); function changeTest(v: number) { console.log('v', v); router.push({ name: 'login', params: userinfo }); /* 不能将类型“{ name: string; age: number; hobby: { computer: boolean; want: string[]; }; }”分配给类型“RouteParamsRaw”。 属性“hobby”与索引签名不兼容。ts(2322) (property) LocationAsRelativeRaw.params?: RouteParamsRaw | undefined */ } </script>

分析

node_modules\vue-router\dist\vue-router.d.ts文件

看到RouteParamsRaw的类型

ts
/** * @internal */ export declare interface LocationAsRelativeRaw { name?: RouteRecordName; params?: RouteParamsRaw; }

继续查找,以下三行就是关键代码

ts
export declare type RouteParamsRaw = Record<string, RouteParamValueRaw | Exclude<RouteParamValueRaw, null | undefined>[]>; /** * @internal */ export declare type RouteParamValue = string; /** * @internal */ export declare type RouteParamValueRaw = RouteParamValue | number | null | undefined;

关键是第一行代码, Record作为ts的映射类型, Exclude作为ts的过滤类型过滤T中可以赋值给K的类型

export declare type RouteParamsRaw = Record<string, RouteParamValueRaw | Exclude<RouteParamValueRaw, null | undefined>[]>;
  • Record解读
ts
interface people { name: string, age: number } type RecordResult1 = Record<string, people>; /* interface people { name: string, age: number } type RecordResult1 = Record<string, people>; */ const a: RecordResult1 = { userinfo: { name: 'xm', age: 18 } }
  • Exclude解读
type RouteParamValueRaw = string | number | null | undefined; type ExcludeRes = Exclude<RouteParamValueRaw, null | undefined>[] // (string | number)[]

最终的类型为:

ts
export declare type RouteParamsRaw = Record<string, RouteParamValueRaw | Exclude<RouteParamValueRaw, null | undefined>[]>; { [X:string]: string | number | null | undefined } | { [X:string]: (string | number)[] }

所以结论:params的值必须为是一个对象,且对象的属性名必须为字符串,属性值可以是string | number | null | undefined或者(string | number)[],所以对于对象需要采用JSON.stringify()转为字符串

报错情况2

params-lost

官方解答

解决方案

  1. 将数据放在本地存储或piniavuex状态管理器中,共多个页面共享
  2. 通过query传参,或者将数据放到路由参数上(即:动态路由传参)
  3. 使用state将其保存到history上,通过window.history.state获取
vue
<script setup lang="ts"> const userinfo = reactive({ name: 'xm', age: '19', hobby: { computer: 'true', want: ['a', 'b'] } }); const router = useRouter(); function changeTest() { router.push({ name: 'register', state: { name: userinfo.name, age: userinfo.age, hobby: JSON.stringify(userinfo.hobby) } }); } </script> <template> <router-link :to="{ name: '/login', state: { name: userinfo.name, age: userinfo.age, hobby: JSON.stringify(userinfo.hobby) } }">登录</router-link> <button @click="changeTest">注册</button> </template>

path跳转与query传参

说明

使用query传的参数以?形式拼接在地址后面

  • EG:
sh
http://192.168.100.106:3345/login/xm/19/%7B%22computer%22:%22true%22,%22want%22:[%22a%22,%22b%22]%7D

EG

  • 路由跳转
vue
<script setup lang="ts"> const userinfo = reactive({ name: 'xm', age: '19', hobby: { computer: 'true', want: ['a', 'b'] } }); const router = useRouter(); function changeTest(v: number) { if (v === 1) { router.push({ name: 'login', params: { name: userinfo.name, age: userinfo.age, hobby: JSON.stringify(userinfo.hobby) } }); } else { router.push({ path: '/register', query: { name: userinfo.name, age: userinfo.age, hobby: JSON.stringify(userinfo.hobby) } }); } } </script> <template> <div> <el-button type="primary" plain @click="changeTest(1)">登录</el-button> <el-button type="primary" plain @click="changeTest(2)">注册</el-button> <RouterLink to="/register">跳转注册页面</RouterLink> </div> <RouterView></RouterView> </template> <style scoped></style>
  • 对应的组件内获取传递的参数

通过useRoute.query方法获取

vue
<template> <div>注册界面</div> </template> <script setup lang="ts"> const route = useRoute(); console.log('params注册', route.query, window.history.state); </script> <style></style>
  • ResultEG:

query

报错情况1

ts
router.push({ path: '/register', query: { name: true, age: { a: 1 } } }); // 不能将类型“true”分配给类型“LocationQueryValueRaw | LocationQueryValueRaw[]”

分析

node_modules\vue-router\dist\vue-router.d.ts文件

ts
/** * @internal */ export declare interface RouteQueryAndHash { query?: LocationQueryRaw; hash?: string; }

查找LocationQueryRaw,可以看到:

ts
export declare type LocationQueryRaw = Record<string | number, LocationQueryValueRaw | LocationQueryValueRaw[]>; export declare type LocationQueryValue = string | null; export declare type LocationQueryValueRaw = LocationQueryValue | number | undefined;

所以可以得知query传参必须为一个对象,对象的属性名为字符串或数字,对象的属性值必须为string | number | null | undefined或者(string | number | null | undefined)[]; 所以如果属性值是一个对象则需要采用JSON.stringify()转为字符串

重定向和别名

重定向

同样和vue-routerv3版本没多大区别,可以直接通过对象{path:'路由路径'}或者{name:'路由名称'}跳转

ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; const StaticRoutes: RouteRecordRaw[] = [ { path: '/', name: 'home', // redirect: { path: '/register' }, redirect: { name: 'register' } component: () => import('@views/IndexView.vue'), children: [ { path: '/login/:name/:age/:hobby', name: 'login', props: true, component: () => import('@views/Login/LoginView.vue'), }, { path: '/register', name: 'register', component: () => import('@views/Register/RegisterView.vue'), }, ], }, ]; const router = createRouter({ history: createWebHistory(), routes: StaticRoutes, }); export default router;

也可以是一个方法,返回重定向目标

ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; const StaticRoutes: RouteRecordRaw[] = [ { path: '/', name: 'home', redirect: () => { return { path: '/login/1/2/3' }; }, component: () => import('@views/IndexView.vue'), children: [ { path: '/login/:name/:age/:hobby', name: 'login', props: true, component: () => import('@views/Login/LoginView.vue'), }, { path: '/register', name: 'registers', component: () => import('@views/Register/RegisterView.vue'), }, ], }, ]; const router = createRouter({ history: createWebHistory(), routes: StaticRoutes, }); export default router;

别名

vue-router3不同,由于官方解答的修复,根据官方文档得知如果路由中包含参数,则别名也必须含有对应的参数

ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; const StaticRoutes: RouteRecordRaw[] = [ { path: '/', name: 'home', component: () => import('@views/IndexView.vue'), children: [ { path: '/login/:name/:age/:hobby', name: 'login', props: true, alias: '/logins/:name/:age/:hobby', component: () => import('@views/Login/LoginView.vue'), }, { path: '/register', name: 'registers', component: () => import('@views/Register/RegisterView.vue'), }, ], }, ]; const router = createRouter({ history: createWebHistory(), routes: StaticRoutes, }); export default router;

本文作者:RKLS

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!