Vue-路由
让页面 构建单页应用变得简单 . 标签会根据不同url来显示不同的页面效果
CDN : https://lib.baomitu.com/vue-router/4.0.14/vue-router.cjs.js (opens new window)
API : https://router.vuejs.org/ (opens new window)
关键字 : router
、routes
脚手架 : Vue-Cli 路由应用
工作原理 :
前端路由 , 指的是 Hash 地址与组件之间的对应关系
用户点击了页面上的路由链接
导致了 URL 地址栏中的 Hash 值发生了变化
前端路由监听了到 Hash 地址的变化
前端路由把当前 Hash 地址对应的组件渲染都浏览器中
注意
- js库引入顺序 优先引入vue后则引入vue-router(基于vue运行的)
- 路由的参数传递 需要到 $route对象 (opens new window) 进行传递参数
router-link
标签 渲染默认是 a标签 , 如有想渲染其他标签 , 可通过tag
属性值 为指定的标签名
应用步骤:
引入 vue 和 vue-router库
设置 HTML内容
<div id="app"> <!-- router-link 最终会被渲染成a标签 , to指定路由的跳转地址 --> <router-link to="/users">用户管理</router-link> <router-link to="/home">首页展示</router-link> <!-- 路由匹配到的组件将渲染在这里 --> <router-view></router-view> </div>
创建 路由对应的Vue组件的模板
let Home = { template: '<div>这是Home内容</div>' }; let Users = { template: '<div>这是用户管理内容</div>' };
配置路由规则
routes
不建议更变 (在实例对象中 , 如果更变了名称则匹配不到该对象let routes = [ { path: '/users', component: Users } { path: '/home', component: Home } ];
实例路由对象
router
不建议更变 (在实例对象中 , 如果更变了名称则匹配不到该对象let router = new VueRouter({ routes })
router实例 挂载到 vue实例上
new Vue({ el: '#app', router })
示例
<div id="app">
<!-- 2. 设置HTMl内容 -->
<!-- router-link 最终会想渲染成a标签 , to指定路由的跳转地址 -->
<router-link to="/home">主页</router-link>
<router-link to="/top">热点</router-link>
<router-link to="/abouts">关于</router-link>
<!-- <显示的内容> -->
<router-view></router-view>
</div>
<!-- 1. 引入库 -->
<script src="vue.js"></script>
<script src="vue-router.js"></script>
<script>
// 4. Vue组件
let Home = {
template:"<div>主页内容</div>"
}
let Top = {
template:"<div>热点内容</div>"
}
let Abouts = {
template:"<div>关于内容</div>"
}
// 3. 设置路由规则
let router = new VueRouter({
routes: [
{path:"/home",component: Home },
{path:"/top",component: Top },
{path:"/abouts",component: Abouts }
]
});
// 5. 把router实例挂载到vue实例上
new Vue({
el: "#app",
router
});
</script>
# 路由导航
官方说明 : https://router.vuejs.org/ (opens new window)
# 声明式导航
路由的 to属性 可提高路由的利用和便捷
常规跳转
<router-link to="/aaa">aaa</router-link>
变量值
<router-link :to="aaa">aaa</router-link>
对象name跳转
<router-link :to="{name:'aaa'}">aaa</router-link>
对象path跳转
<router-link :to="{path:'/aaa'}">aaa</router-link>
带参数跳转
<router-link :to="{name:'aaa',params:{id:1,name:'张三'}}">aaa</router-link>
示例
<div id="app">
<!-- 常规 -->
<router-link to="/aaa">aaa</router-link>
<!-- 变量 -->
<router-link :to="bbb">bbb</router-link>
<!-- 对象name -->
<router-link :to="{name:'ccc'}">ccc</router-link>
<!-- 对象path -->
<router-link :to="{path:'/ddd'}">ddd</router-link>
<!-- 带参数跳转 -->
<router-link :to="{name:'eee',params:{id:1,name:'张三'}}">eee</router-link>
<br>
<router-view></router-view>
</div>
...
<script>
let AAA = {
template:'<div>AAA</div>'
}
let BBB = {
template:'<div>BBB</div>'
}
let CCC = {
template:'<div>CCC</div>'
}
let DDD = {
template:'<div>DDD</div>'
}
let EEE = {
template:'<div>EEE<br>参数: {{$route.params.id}} : {{$route.params.name}} </div>'
}
let router = new VueRouter({
routes:[{
path:"/aaa",
component: AAA
},{
path:"/bbb",
component: BBB
},{
name:"ccc",
path:"/ccc",
component: CCC
},{
path:"/ddd",
component: DDD
},{
name:"eee",
path:"/eee",
component: EEE
}]
})
new Vue({
el:"#app",
data:{
bbb:'/bbb'
},
router
})
</script>
# 编程式导航
以 点击事件形式 来点击某一标签 , 实现路由跳转功能
关键字:this.$router.push(...)
在 Vue容器添加方法用于 事件响应 , 执行 this.$router.push
对象
<方法名>() {
this.$router.push({
path:<路由地址>
});
}
也可通过以下方式进行导航
import {useRouter} from "vue-router";
const router = useRouter();
// 事件触发
router.push(Object);
示例(按钮实现路由AAA
<div id="app">
<router-link to="/aaa">aaa</router-link>
<button @click="toAAA">aaa编程式</button>
<router-view></router-view>
</div>
...
<script>
let AAA = {
template:'<div>AAA</div>'
}
let router = new VueRouter({
routes:[{
path:'/aaa',
component:AAA
}]
});
new Vue({
el:"#app",
data:{},
methods:{
toCCC() {
this.$router.push({
path:"/aaa"
});
}
},
router
});
</script>
当你点击
<router-link>
时 , 这个方法会在内部调用 , 所以说 , 点击<router-link :to="...">
等同于调用router.push(...)
.
# 路由传参
动态路由 是 通过在跳转过程对参数的一个携带过程 , 在当中有两种方式进行传递数据
- 原生URL
- 动态路由Path携带 (REST风格)
# 声明式
设置HTML内容 , 并引入参数 (假如传递参数 : =={name: '张三', age: 23}==
<!-- 原生URL传参 --> <router-link to="/item?name=张三&age=23">张三1</router-link> <!-- 动态路由传参 --> <router-link to="/item/张三/23"></router-link>
动态路由规则 动态参数进行接收 , 接收方式
:<参数名>
(参数的属性名称随意new VueRouter({ routes:[ {path:'/item/:name/:age',component: ...} ] })
**PS:**原生URL传递无需经通过第二步骤进行 Path路由地址的设置
三种传递方式接收各有不同 (因 $route对象 (opens new window) 存储参数位置不一样
- 原生URL : ==this.$route.query.<参数名>==
- 动态路由 : ==this.$route.params.<参数名>==
- 组件传递 : 点击跳转
**PS:**路由跳转时可在组件中添加
update()
函数 , 在DOM重新渲染后 , 对数据进行打印
示例:
<div id="app">
<router-link to="/item?id=23">小明</router-link>
<router-link to="/item?id=23&name=小华">小华</router-link>
<router-link to="/item/33/小军">小军</router-link>
<router-view></router-view>
</div>
....
<template id="show">
<div>
<p>传递的数据查看</p>
<ul>
<li>params.id: {{this.$route.params.id}}</li>
<li>params.name: {{this.$route.params.name}}</li>
<li>params.age: {{this.$route.params.age}}</li>
<li>query.id: {{this.$route.query.id}}</li>
<li>query.name: {{this.$route.query.name}}</li>
<li>query.age: {{this.$route.query.age}}</li>
</ul>
</div>
</template>
<script>
let Items = {
template: "#show",
// DOM 重新渲染完成后被调用 (用于测试
updated() {
console.log(this.$route);
}
}
let router = new VueRouter({
routes: [
{path: '/item/:id', component: Items},
{path: '/item/:id/:name/:age', component: Items}
]
})
new Vue({
el: "#app",
router
})
</script>
# 编程式
跳转方
const router = useRouter();
// 事件触发
router.push({
path: '/user/list',
// 传递的参数
query: {...}
});
接收方
const route = useRoute();
console.log(route.query)
# 组件props属性路由传参
vue-router 允许在路由规则中开启 props 传参 , 才能以组件的形式进行接收参数
{ path: '/product/:id', component: Product, props: true }
<template>
<h1>Product组件</h1>
<!-- 获取动态的id值 -->
<p>{{id}}</p>
</template>
<script>
export default {
// 组件的名称
name: 'Product',
props : [id]
}
</script>
# Vue3
不同页面传递数据
- url 跳转url携带query
- url 衔接形式(/team/:id)
- hash
- 全局变量
# Redirect重定向
当某个页面被强制中转时 , 采用 redirect 进行路由重定向
关键字:redirect
步骤: 在原有的路由组件里 添加新 属性 ==redirect : <路由地址>==
routes:[{
path : <默认路由地址>,
redirect : <重定向路由地址>
}]
实例:(将 /bbb
路由强制中转至 /aaa
<div id="app">
<router-link to="/aaa">aaa</router-link>
<router-link to="/bbb">bbb</router-link>
<router-link to="/ccc">ccc</router-link>
<router-view></router-view>
</div>
....
<script>
let AAA = {
template:'<div>AAA</div>'
}
let BBB = {
template:'<div>BBB</div>'
}
let CCC = {
template:'<div>CCC</div>'
}
let router = new VueRouter({
routes:[{
path:'/aaa',
component:AAA
},{
path:'/bbb',
redirect:"/aaa",
component:BBB
},{
path:'/ccc',
component:CCC
}]
});
new Vue({
el:"#app",
data:{},
router
});
</script>
# 路由激活样式
路由激活会产生样式 ==calss="router-link-exact-active router-link-active"== , 该类会伴随着激活出现
<a href="..." class="router-link-exact-active router-link-active">切换页面1</a>
以上的 激活样式的系统类名 , 一般不建议直接覆盖系统默认的样式 , 因此官方提供有方式修改其样式
自定义路由激活class样式 :在路由规则中 添加 linkActiveClass
属性其值为 class名
路由激活渲染示例: (la-active为自定义样式的class名)
<a href="..." class="router-link-exact-active la-active">切换页面1</a>
# 路由嵌套
路由嵌套和二级菜单 类似 , 但二级路由的嵌套是通过组件模板中再次添加路由 , 从而实现路由嵌套的效果
关键字:children
应用步骤:
- 在一级路由组件的
component
模板中 添加二级路由的模板 - 在一级路由的路由规则里 添加属性
children
数组 - 在
childern
数组 中配置二级路由规则与模板
let routes = [{
path: <一级路由地址>,
component: <一级路由模板>,
children: [
{path: <二级路由地址>, component: <二级路由模板>}
[,{path: <二级路由地址>, component: <二级路由模板>}...]
]
}
[,{path: <一级路由地址>, component: <一级路由模板2>}...]
]
注意
该路由为子路由 , 那么无需再次编辑一级路径地址 , 也可无需添加反斜杠
示例1
<div id="app">
<router-link to="/home">主页</router-link>
<router-link to="/music">音乐</router-link>
<router-view></router-view>
</div>
...
<script>
let Home = {
template:'<div>Home---</div>'
}
let Music = {
template: '<div>MUSIC---' +
'<router-link to="/music/pop">流行</router-link>' +
'<router-link to="/music/cal">古典</router-link>' +
'<router-view></router-view>' +
'</div>'
}
//二级组件
let Detail = {
template: '<div>Detail--{{$route.params.name}}</div>'
}
let router = new VueRouter({
routes:[{
name:'default',
path:'/',
component: Home
},{
name:'home',
path:'/home',
component: Home
},{
name:'music',
path:'/music',
component: Music,
// 子路由
children:[{
path:'/music/:name',
component: Detail
}]
}]
});
new Vue({
el:"#app",
data:{},
router
});
</script>
示例2
<style>
.box-red {
background: red;
height: 200px;
}
.box-blue {
background: blue;
height: 200px;
}
.box-green {
background: green;
height: 200px;
}
</style>
....
<div id="app">
<router-link to="/one">路由页面1</router-link>
<router-link to="/two">路由页面2</router-link>
<router-view></router-view>
</div>
....
<template id="one">
<div class="box-green">
<p>一级one</p>
<router-link to="/one/onesub1">路由页面1</router-link>
<router-link to="/one/onesub2">路由页面2</router-link>
<router-view></router-view>
</div>
</template>
<template id="onesub1">
<div class="box-red">
<p>二级one</p>
</div>
</template>
<template id="onesub2">
<div class="box-blue">
<p>二级one</p>
</div>
</template>
<template id="two">
<div class="box-green">
<p>一级two</p>
</div>
</template>
<script>
let One = {
template: "#one"
}
let Two = {
template: "#two"
}
let OneSub1 = {
template: "#onesub1"
}
let OneSub2 = {
template: "#onesub2"
}
let routes = [
{path: "/", redirect: '/one'},
{
path: "/one",
component: One,
children: [
{path: "onesub1", component: OneSub1},
{path: "onesub2", component: OneSub2}
]
},
{path: "/two", component: Two}
]
let router = new VueRouter({
routes
})
new Vue({
el: "#app",
router
})
</script>
# 命名视图
命名视图 是让不同出口显示不同内容(和 具名插槽 类似)
当路由地址被匹配时同时制定多个出口 , 并且每个出口显示的内容不一样
应用步骤:
- 为
router-view
标签 添加 name属性(指定出口类型的模板 - 在 路由规则配置中 将路由模板从
component
属性 改为components
属性 (添加模板组
let router = new VueRouter({
routes: [{
path: <路由地址>,
// key值 对应路由出口的 name属性值
components: {
<key>: <模板1>
[,<key>: <模板2>...]
}
}]
})
示例
<div id="app">
<router-view></router-view>
<router-view name="name1"></router-view>
<router-view name="name2"></router-view>
</div>
....
<template id="one">
<div>
<p>第一个模板</p>
</div>
</template>
<template id="two">
<div>
<p>第二个模板</p>
</div>
</template>
<script>
let One = {
template: "#one"
}
let Two = {
template: "#two"
}
// 首次打开网页URL路由地址为 '/'
let routes = [{
path: "/",
components: {
name1: One,
name2: Two
}
}]
let router = new VueRouter({
routes
})
new Vue({
el: "#app",
router
})
</script>
渲染结果:
<div id="app">
<!---->
<div><p>第一个模板</p></div>
<div><p>第二个模板</p></div>
</div>
三个出口:
- 未指定出口名称因此没有显示
- 指定出口名称为 name1 -> One
- 指定出口名称为 name2 -> Two
# 路由监听
[watch属性](/vue/03/#watch 数据监听) 不仅仅能够监听数据的变化 , 还能够监听路由地址的变化
监听方式:
watch: {
"$route.path"(newV, oldV) {
console.log(newV, oldV)
}
}
# 导航守卫
导航守卫可以控制路由的访问权限 . 全局导航守卫会拦截每个路由规则 , 从而对每个路由进行访问权限的控制
router.beforeEach
注册一个全局前置守卫 :
// to: 目标路由 & from 来自路由 & 执行跳转路由(下一个)
router.beforeEach((to, from, next) => {
if (to.path === '/main' && !isAuthenticated) {
next('/login')
}
else {
next()
}
})
在守卫方法中如果声明了 next 形参,则必须调用 next() 函数 , 否则不允许用户访问任何一个路由!
- 直接放行 : next()
- 强制其停留在当前页面 : next(false)
- 强制其跳转到登录页面 : next('/login')