当前位置: 首页 > news >正文

Vue-Router详解【学习Vue-Router看这一篇就够了!!!】

目录

前言

安装

Vue-Router简介

Vue-Router介绍

Vue-Router的简单使用

注意

标签

带参数的动态路由

什么是带参数的动态路由

路由参数匹配

注意

路由参数匹配的语法规则

加号“+“的使用:

乘号“*”的使用

问号“?”的使用

路由的嵌套

路由跳转

使用路由方法

路由命名

拼接参数实现路由跳转

push方法返回Promise对象

路由历史控制

页面不进入history栈的跳转

使用history灵活跳转到某个位置

路由的命名

使用名称进行路由切换

路由视图命名

默认名字default

使用别名

路由重定向

关于路由传参

同级多个子路由

固定的props值

props是一个函数

动态路由

动态添加路由

动态删除路由

获取现有路由

前言

本文默认您已了解或掌握Vue3的基本用法

Vue(3.0版本以上均可) + Vite + Vue-Router(最新版本即可)

参考资料

  • Vue官方中文文档:Vue.js - 渐进式 JavaScript 框架 | Vue.js
  • Vue-Router中文官方文档:入门 | Vue Router

更多Vue系列文章,请关注博主【Vue全家桶】专栏:Vue全家桶-专栏

安装

推荐使用“npm”安装

npm install vue-router@4

官网安装速度较慢,可以使用“cnpm”替换“npm

npm install vue-router@4

Vue-Router简介

Vue-Router介绍

学习Vue-Router之前,我们有必要了解,Vue-Router是干什么的???

Vue-Router是一个路由管理插件,它可以解析浏览器中的“URL”并跳转到不同界面,Vue-RouterVue的单页面提供了更大的可能性!!

Vue-Router的简单使用

Vue-Router使用的简单概括为:

创建一个路由,放置<router-view>路由页面出口,配置路由,最后改变URL即可实现切换页面!

下面是一个简单的例子,帮我们了解Vue-Router的具体实现逻辑

  • 首先创建名为“Demo1.vue”和“Demo2.vue”两个vue文件

  • 两个文件中编写如下代码:

Demo1.vue

<script setup>
</script><template><h1>这里是Demo1页面</h1>
</template>

Demo2.vue

<script setup>
</script><template><h1>这里是Demo2页面</h1>
</template>
  • 修改App.vue(你的根组件文件)文件,代码如下:

App.vue

<script setup>
</script>
<template><h1>这里是主页面</h1><!-- router-link是路由的入口,用来切换不同到的路由页面 --><p><router-link to="/demo1">前往页面1</router-link></p><p><router-link to="/demo2">前往页面2</router-link></p><!-- router-view是理由页面的出口 用来渲染路由页面 --><router-view></router-view>
</template>
  • 修改项目的main.js文件:

main.js

import {createApp} from 'vue'
//引入必要的路由方法
import {createRouter,createWebHashHistory} from 'vue-router'//引入根组件和页面组件
import App from './App.vue'
import Demo1 from './components/Demo1.vue'
import Demo2 from './components/Demo2.vue'//创建路由配置
const routerConfig = [{path:'/demo1',component:Demo1},{path:'/demo2',component:Demo2}
]
//创建路由对象
const router = createRouter({history:createWebHashHistory(),routes:routerConfig
})
const app = createApp(App)//注册路由
app.use(router)
app.mount('#app')

至此,我们已经配置好所有的设置,打开页面后,页面已经可以正常显示,并且可以正常跳转:

注意

通过上面一个简单的小例子,相信您对Vue-Router的实现页面跳转已经有了大体的了解,下面我们来概括一下Vue-Router的具体实现方式:

  1. 配置根组件页面,在该组件页面中放置<router-view>路由出口,用来容纳不同页面渲染的具体位置(其实根本来说,Vue-Router实现的是将一个页面中的部分/全部区域进行页面跳转)
  2. 配置页面组件
  3. 通过切换不同的URL来实现页面跳转(切换不同的URL三种方式,后面会提到)

<router-link>标签

<router-link>标签类似于传统HTML中的<a>标签,只不过<router-link>标签中通过“to”来指定目标URL

to的值可以是:“一个合法的URL路径字符串”和“一个合法的URL路径字符串变量(:to绑定)

<script setup>const path = 'demo1'
</script>
<template><p><router-link to="/demo1">前往页面1</router-link></p><!-- 等同于上面的to='/demo1' --><p><router-link :to=path>前往页面1</router-link></p>
</template>

带参数的动态路由

什么是带参数的动态路由

试想一个场景,例如某个网站中的“用户中心”页面,不同用户所展示的信息固然是不同的,要想不同的用户渲染出各自的数据,我们可以通过“为路由添加参数”实现

一个利用参数URL渲染不同用户信息的例子:

一个B站UP主的个人主页URL

  • 这里的293846287就是B站用户UUID的参数,通过这个参数来渲染不同的用户主页

路由参数匹配

我们通过编写一个简单的用户中心例子,来讲解路由参数

  • 我们创建一个User.vue文件,编写代码如下:

User.vue

<script setup>
</script>
<template><h1>姓名:{{ $route.params.username }}</h1><h1>ID:{{ $route.params.id }}</h1>
</template>
  • 配置“main.js”中路由:
import {createApp} from 'vue'
//引入必要的路由方法
import {createRouter,createWebHashHistory} from 'vue-router'//引入根组件和页面组件
import App from './App.vue'
import User from './components/User.vue'  //创建路由配置
const routerConfig = [{path:'/user/:username/:id',component:User}
]
//创建路由对象
const router = createRouter({history:createWebHashHistory(),routes:routerConfig
})
const app = createApp(App)//注册路由
app.use(router)
app.mount('#app')
  • 最后手动输入URL

效果

注意

我们的URL路由配置:“/user/:username/:id”,各参数作用如下:

  • 冒号(':'):放在字符串前面,表示两个“/”之间的参数是一个路由变量,用户实际填写的URL参数会存储到该路由变量

<template>标签中通过“$route”全局变量下的params属性来使用具体路由变量

路由参数匹配的语法规则

Vue-Router允许参数内部使用【正则表达式】来进行参数匹配

由于正则表达式并不属于本文讲述内容,在这里不再赘述,只简单解释两个字符表达式:

  • *”:用来匹配多个或0个字符
  • +”:用来匹配至少一个字符

下面通过一个例子,来说明正则表达式的使用:

加号+“的使用:

  • 新建一个“UserSetting.vue”文件,编写代码如下:

UserSetting.vue

<script setup>
</script>
<template><h1>用户设置</h1><h2>id:{{ $route.params.id }}</h2>
</template>
  • 修改main.js中的路由配置

main.js

import {createApp} from 'vue'
//引入必要的路由方法
import {createRouter,createWebHashHistory} from 'vue-router'//引入根组件和页面组件
import App from './App.vue'
import User from './components/User.vue'  
import UserSetting from './components/UserSetting.vue'//创建路由配置
const routerConfig = [{path:'/user/:username',component:User},{// \\d+表示只匹配数字path:'/user/:id(\\d+)',component:UserSetting}
]
//创建路由对象
const router = createRouter({history:createWebHashHistory(),routes:routerConfig
})
const app = createApp(App)//注册路由
app.use(router)
app.mount('#app')
  • 此时我们已经完成【正则表达式】匹配路由的所有设置,尝试输入“/user/小王”与“/user/666”查看页面有何不同

乘号“*”的使用

  • 创建一个“Category.vue”文件,编写代码如下:

Category.vue

<script>
</script>
<template><h1>类别</h1><h2>{{ $route.params.cat }}</h2>
</template>
  • 修改main.js中的路由配置

main.js

import {createApp} from 'vue'
//引入必要的路由方法
import {createRouter,createWebHashHistory} from 'vue-router'//引入根组件和页面组件
import App from './App.vue'
import Category from './components/Category.vue'//创建路由配置
const routerConfig = [{// cat*用来匹配多级URLpath:'/category/:cat*',component:Category}
]
//创建路由对象
const router = createRouter({history:createWebHashHistory(),routes:routerConfig
})
const app = createApp(App)//注册路由
app.use(router)
app.mount('#app')
  • 最后我们输入URL看看页面发生了什么变化,“/category/参数1/参数2/参数3

可以看到所有的参数变成了一个列表,“*”号的一个重要作用就是匹配多级参数

问号“?”的使用

问号“?”的作用是表示参数是可选的,可有可无

例如根据上面乘号“*”的例子,我们修改main.js中代码:

{// ?表示参数可选path:'/category/:cat?',component:Category
}

路由的嵌套

在前面,我们定义了很多路由,但是真正渲染路由的地方只有一个,即那唯一的一个“<router-view>”,这类路由实际上被叫做“顶级路由”(即路由在根组件中渲染)

但在实际开发中,我们可能需要在某个“子组件”内,单独渲染路由,此时就需要叫作“路由的嵌套

现在假设“某组件中需要渲染好友列表”,例子如下:

  • 创建一个“Friends.vue”文件,编写代码如下:

Friends.vue

<script setup>
</script>
<template><h1>好友列表</h1><h2>好友人数:{{ $route.params.count }}</h2>
</template>
  • 修改User.vue 

User.vue

<script setup>
</script>
<template><h1>用户中心</h1><h2>姓名:{{ $route.params.username }}</h2><router-view></router-view>
</template>
  • 修改main.js中的路由配置

main.js

import {createApp} from 'vue'
//引入必要的路由方法
import {createRouter,createWebHashHistory} from 'vue-router'//引入根组件和页面组件
import App from './App.vue'
import User from './components/User.vue'
import Friends from './components/Friends.vue'//创建路由配置
const routerConfig = [{path:'/user/:username/',component:User,// children表示该路由下的子路由// 注意:子路由的URL拼接紧凑着父路由// 例如:想访问子路由,完整的URL为:‘/user/username/friends/:count’// 子路由前面不能加一个/children:[{path:'friends/:count',component:Friends}]}
]
//创建路由对象
const router = createRouter({history:createWebHashHistory(),routes:routerConfig
})
const app = createApp(App)//注册路由
app.use(router)
app.mount('#app')
  • 最后,输入“/user/小王/friends/100

路由跳转

路由跳转,除了我们已经介绍过的<router-link>进行跳转,还可以使用函数的方式进行路由跳转

使用路由方法

当我们成功向Vue注册路由后,在任何Vue实例中,都可以通过$route属性访问路由对象

通过调用路由对象的push方法可以向history栈添加一个新的记录

下面是一个例子

  • 修改App.vue,代码如下:
import {createApp} from 'vue'
//引入必要的路由方法
import {createRouter,createWebHashHistory} from 'vue-router'//引入根组件和页面组件
import App from './App.vue'
import User from './components/User.vue'//创建路由配置
const routerConfig = [{path:'/user/:username',component:User}
]
//创建路由对象
const router = createRouter({history:createWebHashHistory(),routes:routerConfig
})
const app = createApp(App)//注册路由
app.use(router)
app.mount('#app')
  • 修改App.vue,代码如下:
<script setup>import { useRouter } from 'vue-router'const router = useRouter()function toUser() {router.push('/user/小王')}
</script>
<template><h1>这里是主页面</h1><button @click="toUser">用户中心</button><router-view></router-view>
</template>

注意:上面使用的是Vue3.4版本更新后的setup语法糖,在setup语法糖中并没有“$route”属性,但是我们可以使用“useRouter”方法返回一个“route”对象

在这里,给出传统export模式的一个写法(export模式下,使用$route没有任何问题):

<script>export default {methods:{toUser(){this.$router.push('/user/小王')}}}
</script>
<template><h1>这里是主页面</h1><button @click="toUser">用户中心</button><router-view></router-view>
</template>

效果:

由此可见,使用push()方法进行路由跳转,与使用<router-link>标签进行路由跳转效果是一样的

路由命名

我们可以在定义一个路由的使用,通过指定name属性来给路由设置一个名字,这样,后面使用该路由的时候,可以直接通过路由的名字定位到该路由

{path:'/user/:username',component:User,//通过name属性指定路由名字,此时这条路由的名字就叫做'user'name:'user'
}

拼接参数实现路由跳转

在使用push()方法进行路由跳转时,除了可以直接使用URL进行跳转,我们还可以使用路由的名字进行跳转

下面是一个例子

  • 修改main.js,代码如下:

main.js

import {createApp} from 'vue'
//引入必要的路由方法
import {createRouter,createWebHashHistory} from 'vue-router'//引入根组件和页面组件
import App from './App.vue'
import User from './components/User.vue'//创建路由配置
const routerConfig = [{path:'/user/:username',component:User,name:'user'}
]
//创建路由对象
const router = createRouter({history:createWebHashHistory(),routes:routerConfig
})
const app = createApp(App)//注册路由
app.use(router)
app.mount('#app')
  • 修改App.vue

App.vue:

<script setup>import { useRouter } from 'vue-router'const router = useRouter()function toUser() {router.push({name:'user',params:{username:'小王'}})}
</script>
<template><h1>这里是主页面</h1><button @click="toUser">用户中心</button><router-view></router-view>
</template>

通过params参数来添加拼接URL的参数,而name指定需要拼接的路由名字

但如果路有需要查询参数,此时我们可以通过query属性进行设置:

//会被处理成 /user?id=xixixi
router.push({path:'/user',query:{id:'xixixi'}
})

注意:“如果设置了path属性,那么params属性会被自动忽略” 

push方法返回Promise对象

在使用push方法进行路由跳转时,push方法会返回一个promise对象,可以用其来处理跳转成功之后的逻辑

router.push({path:'/user',query:{id:'xixixi'}}).then(() => {console.log("跳转成功")
})

路由历史控制

当我们使用<router-link>标签或者push()方法进行路由跳转时,新的路由实际上会被放入history栈中,我们可以操控history栈从而实现更精确的页面跳转控制

页面不进入history栈的跳转

某些特殊的情况下,我们可能希望页面直接跳转,并且无法从新页面回退到旧页面,此时我们可以使用:“replace参数”或“replace方法”来直接替换掉当前页面

它的工作原理是:“用新页面直接替换掉当前页面,旧页面不会进入导航栈,自然无法回退

this.$router.push({path:'/user/小王',replace:true
})
//等同于
this.$router.replace({path:'/user/小王'
})

注意:“这里使用的是this.$router实际上就是使用export模式下的导出,如果使用setup语法糖,需要自己设置router属性,上面已经提到过,这里不再赘述

使用history灵活跳转到某个位置

//跳转到后一个页面
this.$router.go(1)
//跳转到前一个页面
this.$router.go(-1)
//跳转到前两个页面
this.$router.go(-2)

路由的命名

路由的命名前面已经简单提到过,在这里我们再详细的说一下

通过设置name属性为路由指定名字,使用name属性的优势:“避免硬编码URL”、“自动处理参数编码

使用名称进行路由切换

  • 使用push切换
this.$router.push({name:'user',params:{username:'小王'    }
})
  • 使用<router-link>切换
<router-link :to="{name:'user',params:{username:'小王'}}">小王</router-link>

路由视图命名

路由视图命名是指对<router-view>标签进行命名

如果某个组件下面有两个“同级子路由”,这个时候就需要对<router-view>进行命名,用来区分两个不同的子路由

使用“name”属性对路由命名

一个例子如下:

  • 修改App.vue,代码如下:

App.vue

<script setup>
</script>
<template><div><router-view name="topBar"></router-view></div><div><router-view name="main"></router-view></div>
</template>
  • 修改main.js,代码如下:

main.js

import {createApp} from 'vue'
//引入必要的路由方法
import {createRouter,createWebHashHistory} from 'vue-router'//引入根组件和页面组件
import App from './App.vue'
import User from './components/User.vue'
import UserSetting from './components/UserSetting.vue'//创建路由配置
const routerConfig = [{path:'/home/:username/:id',//注意定义多级路由时,这里使用的是components,而不是component,一个是复数一个是单数components:{topBar:User,main:UserSetting}}
]
//创建路由对象
const router = createRouter({history:createWebHashHistory(),routes:routerConfig
})
const app = createApp(App)//注册路由
app.use(router)
app.mount('#app')
  • 最后,输入“/home/小王/666

效果

默认名字default

对于没有命名的<router-view>,其名字会被默认分配为default

因此,下面的写法与上面是一样的

App.vue

<script setup>
</script>
<template><div><router-view name="topBar"></router-view></div><div><router-view></router-view></div>
</template>

main.js

//创建路由配置
const routerConfig = [{path:'/home/:username/:id',//注意定义多级路由时,这里使用的是components,而不是component,一个是复数一个是单数components:{topBar:User,default:UserSetting}}
]

使用别名

别名提供了一种“路由路径映射”的方式,也就是可以自由地将组件映射到一个任意的路由上,而不受嵌套结构的限制

使用“alias”属性来设置别名

一个例子如下:

//路由配置
const route = [{path:'/user/:id(\\d+)',component:UserSetting,alias:'/setting/:id'}
]//之后,下面两个路径的渲染效果一致
/setting/666/
/user/666/

使用alias属性,可以设置为“字符串”配置一个别名,也可以设置为“数组”配置一组别名

//路由配置
const route = [{path:'/user/:id(\\d+)',component:UserSetting,alias:['/setting/:id','/s/:id']}
]//之后,下面三个路径的渲染效果一致
/setting/666/
/user/666/
/s/666/

路由重定向

重定向会将当前路由映射到另一个路由上,URL会改变

路由重定向别名最大的区别就是,路由重定向会改变URL

例如,当用户需要访问'/d/1'时,需要渲染'/demo1'的页面:

const route = [{path:'/demo1',component:Demo1,name:'Demo'},{path:'/d/1',redirect:'demo1'//也支持使用名字进行重定向//redirect:{name:'Demo'}}
]

关于路由传参

在前面我们在组件中使用$route.params的方式来获取路由参数,这种方法虽然简单,但是不利用组件的复用,因为组件与路由的耦合太强,为此,我们在这里学习“使用外部属性进行传参

一个耦合性很强获取用户名字的例子:

<script setup>
</script>
<template><h1>用户中心</h1><h2>姓名:{{ $route.params.username }}</h2>
</template>

现在我们使用“外部属性”来获取用户名字

<script setup>const {username} = defineProps(['username'])
</script>
<template><h1>用户中心</h1><h2>姓名:{{ username }}</h2>
</template>

main.js修改如下:

const routerConfig = [{path:'/user/:username',component:User,//使用外部属性,需要props设置为trueprops:true}
]

效果:

同级多个子路由

对于多个子路由,我们需要对多个子路由分别进行props设置

const routes = {path:'/home/:username/:id',components:{topBar:User,main:UserSetting},props:{topBar:true,main:true}
}

固定的props值

如果传入的参数是一个固定值,那么我们可以将props的值固定,此时接收到的参数的值就是一个固定值

const router = {path:'/user/:id(\\d+)',component:UserSetting,props:{id:'000'}
}此时访问 /user/6666
获取到的id是000而不是6666

props是一个函数

props还有一种更加强大的使用方式,可以将其设置为一个匿名函数,函数中返回组件的外部属性对象,这种方式动态性很好!

const routerConfig = [{path:'/user/:username',component:User,props:myroute => {return {username:myroute.params.username}}}
]

动态路由

目前为止,我们所使用的路由都是在main.js定义的静态路由,在实际开发中,我们可能需要动态的更新路由,这就叫做动态路由

动态添加路由

使用“addRoute”方法操作“$route”对象来实现动态添加路由

  •  修改Demo1.vue文件,代码如下:

Demo1.vue

<script setup>import {onMounted} from 'vue'import {useRouter} from 'vue-router'import Demo2 from './Demo2.vue'const router = useRouter()onMounted(() => {router.addRoute({path:'/demo2',component:Demo2})})function click(){router.push('/demo2')}
</script><template><h1>Demo1页面</h1><button @click="click">跳转Demo2</button>
</template>
  • 修改main.js文件,代码如下:
const routerConfig = [{path:'/demo1',component:Demo1}
]
  • 输入“/demo1”,观察效果

动态删除路由

  • 当时用addRoute方法添加路由时,如果添加了重名的路由,那么旧路由会被删除
this.$router.push({path:'/demo1',component:Demo1,name:'Demo'
})
//此时,/demo1会失效
this.$router.push({path:'/demo2',component:Demo2,name:'Demo'
})
  • 使用addRoute方法添加路由时,它会返回一个“删除回调”函数,执行该函数可以直接删除添加的路由
let call = this.$router.push({path:'/demo1',component:Demo1,name:'Demo'
})
//直接删除路由
call();
  • 对于已经命名的路由,可使用removeRoute方法删除路由
this.$router.push({path:'/demo1',component:Demo1,name:'Demo'
})//使用removeRoute方法删除命名路由
removeRoute('/Demo');
  • 注意:“当路由被删除时,它所有的别名和子路由也会被同步删除

获取现有路由

使用hasRoute()方法来查询当前路由中的子路由

使用getRoutes()方法来获取$route对象上的所有路由包括子路由,返回一个列表

//接收一个路由名字
this.$router.hasRoute("Demo2")
this.$router.getRoutes()
  • 一个getRoutes()包含多个同级子路由的构造:

main.js配置

const routerConfig = [{path:'/user',components:{topBar:User,main:UserSetting}}
]

 


http://www.mrgr.cn/news/65061.html

相关文章:

  • 你敢想象吗?我能远程控制家里的电脑进入Bios
  • 代码随想录第十七天
  • 实体(Entity)详解
  • 工业通信网关的各项功能解析-天拓四方
  • [Prometheus学习笔记]从架构到案例,一站式教程
  • 清华双臂机器人扩散大模型RDT:先预训练后微调,支持语言、图像、动作多种输入(1B参数)
  • RK3568平台开发系列讲解(SPI篇)SPI 控制器驱动分析
  • 如何使用Get进行状态管理
  • ts:使用typeof运算符输出各对象的类型
  • Linux 信号
  • 算法——递推
  • 各地级市能源消耗量数据-基于灯光数据的反演(2000-2022年)
  • 虚拟内存与物理内存之间的映射关系
  • 无人机场景数据集大全「包含数据标注+划分脚本+训练脚本」 (持续原地更新)
  • 【C++】多态的语法与底层原理
  • Yocto - 使用Yocto开发嵌入式Linux系统_12 开发定制层
  • 基于规则碎纸片的拼接复原模型
  • Nginx 学习指南
  • 清华双臂机器人扩散大模型RDT:先预训练后微调,支持语言、图像、动作多种输入(1B参数)
  • ctfshow(91,96,97)--PHP特性
  • WPF+MVVM案例实战(二十一)- 制作一个侧边弹窗栏(AB类)
  • 基于向量检索的RAG大模型
  • [ shell 脚本实战篇 ] 编写恶意程序实现需求(恶意程序A监测特定目录B出现特定文件C执行恶意操作D-linux)
  • word mathml 创建粗体字母快捷键
  • Mybatis基于注解的关系查询
  • 基于Docker搭建Maven私服仓库