二十八、路由的使用
(一)路由是什么?
路由是实现单页面应用程序的由Vue提供路由工具的页面设计思路和模式。
(二)如何使用?
A、使用路由需要用到三个元素:路由器(里面定制路由规则)、定制化标签(生成链接标签)、main.js中的router配置项
B、路由器配置:
- 下载vue-router的第三版本,来支持vue2
npm i vue-router@3
- 在src下创建router目录,在目录下创建index.js生成路由器
//引入vue-router
import VueRouter from "vue-router";
//引入需要路由器匹配的两大组件
import One from "../components/One.vue";
import Two from "../components/Two.vue";
export default new VueRouter({
routes:[
{
//指定路由规则
path:"/one",
component: One
},
{
path:"/two",
component: Two
}
]
})
C、main.js的引入与使用
//引入vue,从库中
import Vue from 'vue';
//引入管理组件
import App from './App.vue'
//第一步,引入VueRouter
import VueRouter from 'vue-router';
//第二步引入上一步创建的路由器实例
import router from "./router/index";
Vue.config.productionTip = false
//第三步,让Vue应用路由
Vue.use(VueRouter);
new Vue({
el:"#app",
render:function(createElement){ return createElement(App)},
//第四步,给router配置项配置自己生成的路由器
router,
})
D、定制化标签的使用
<div class="insertContainer">
<div class="topContainer">
<div id="top">
<h3>我是盒子的标题</h3>
</div>
</div>
<div class="contentContainer">
<div class="contentLeft">
<!-- 用Vue-router提供的标签定制a标签,和跳转路径
active-class 指定当该标签被路由时的样式
to 指定路由的目标路径
-->
<div class="leftContent">
<router-link active-class="{background-color:blue;}" to="/one">ONE</router-link><br>
<router-link active-class="{background-color:blue;}" to="/two">TWO</router-link>
</div>
</div>
<div class="ContentRight">
<!-- 指定路由到的组件放置位置 -->
<router-view class="rightContent"></router-view>
</div>
</div>
</div>
再加上些简单的样式就可以实现路由了!
点击不同链接,会变化组件内容,一直保持单页面。
(四)嵌套组件
- 在上面例子中路由组件Two加上两个路由,嵌套在其中。
A、首先在路由器中声明新的路由配置
//引入vue-router
import VueRouter from "vue-router";
//引入需要路由器匹配的两大组件
import One from "../pages/One.vue";
import Two from "../pages/Two.vue";
//第一步,引入需要的Two组件需要的路由组件
import TwoOne from "../pages/TwoOne.vue"
import TwoTwo from "../pages/TwoTwo.vue"
export default new VueRouter({
routes:[
{
path:"/one",
component: One
},
{
path:"/two",
component: Two,
//第二步,在路由中注册为路径“/two”的子路由
//特别注意,子路由在路由器中配路径值时,不用加/,底层会加
children:[
{
path:"twoone",
component: TwoOne
},
{
path:"twotwo",
component: TwoTwo
}
]
}
]
})
B、之前已在Vue中注册过VueRouter,所以接着,我们在组件two中加入路由即可
<template>
<div>
<div>我是Two组件中的内容</div>
<hr>
<!-- 注意嵌套的二级路由需要写出完整路径 -->
<router-link active-class="action" to="/two/twoone">动漫人物列表</router-link>
<router-link active-class="action" to="/two/twotwo">一些胡思乱想</router-link>
<router-view></router-view>
</div>
</template>
(五)路由时传递信息
- 这里我们再给二级路由添加三级路由,在三级路由组件被调用时,显示二级路由组件传递的信息
A、二级路由传递信息的方式,采用对象传递参数的方式
数据:
data() {
return {
peoples: ["萧炎", "美杜莎" ,"云韵", "荒天帝"],
infos: ["侥幸哥","美人","云岚宗","太古"],
}
}
结构传参与路由
<ul>
<li v-for="(value, index) in peoples" :key="index">
//to采用对象传参的形式,使传递的信息更丰富 ,query中储存要传递的数据
<router-link :to="{
path: '/two/twoone/twooneone',
query: {
zong: infos[index],
}
}">{{ value }}</router-link>
</li>
<router-view></router-view>
</ul>
三级路由组件接收参数
<ul>
<li>该人物的绰号是{{ $route.query.zong }}</li>
</ul>
接收到的数据会被存到子路由组件$route的query中。
(六)为路由命名
- 当路由嵌套层数过多,可以使用在路由器中给路由命名的方式,来简写to中写法
- 使用name之前:
<router-link :to="{
path: '/two/twoone/twooneone',
query: {
zong: infos[index],
}
}">{{ value }}</router-link>
- 在路由中命名
- 换用name后
<router-link :to="{
name: 'endpath',
query: {
zong: infos[index],
}
}">{{ value }}</router-link>
注意:当to不采用对象写法,直接跟字符串是,默认解读为路径,要用name简写要用对象方式
(七)路由的param参数
- 也是一种传递参数的形式,不过这种是将参数跟路径拼到一块,跟路径写法一致,需要在路由器指定信息。
- 传参前要在路由中指定参数位置
- 传参方式一:
<router-link :to="`/two/twoone/twooneone/${infos[index]}`">
{{ value }}</router-link>
解析:模版字符串中都是文本内容,同时可以使用${}书写表达式
接收端以在路由器中的命名接收,这里是zong
- 传参方式二:
<router-link :to="{
name: 'endpath',
params:{
zong: infos[index]
}
}">{{ value }}</router-link>
</li>
<router-view></router-view>
- 注意:这种传参方式,路由器中必须声明name,并且在to中使用。
(八)路由参数的接收(props的使用)
A、params参数的传递
- 当参数以params的方式发送时,在路由器新加配置项props:true
- 接收方以:props['','']接收即可
children:[
{
name:"endpath",
path:"twooneone/:zong",
component: TwoOneOne,
//这种方式只能使params中的参数以props方式发送,会忽视query参数
props: true,
}
]
export default {
name:"TwoOneOne",
props:["zong"]//zong是to传递参数时params中键的命名
}
B、query参数的传递
- 修改浏览器中props配置,让其可以接受到query数据
//函数声明式,会接受到$route参数,方便指定query
//以return对象的方式将数据返回给,数据接收方的props
//ES6语法,将对象多展开的连续使用
props({query:{zong}}){
return {
zong//简写形式,ES6语法
}
}
- 发送方将参数传递变为query即可
- 接收方不变
(九)路由的浏览模式记录
- 组件之间的路由引起的路径转换会留下浏览记录
- 两种模式
模式调整:
<router-link replace to="/two/twoone">动漫人物列表</router-link>
仅调整该标签对应路由的路由记录模式。
(十)编程式路由导航(router-link标签的替代方法,自定义方式)
- 在之前的例子中,我们都是直接用<router-link>标签来自动生成<a>标签,和路由功能,用to来传递参数和目标地址
- 现在我们利用每个组件都能看到的$router来实现,我们先看一下$router的结构。
- push() 实现组件挂载和历史记录压入
- replace() 实现组件挂载和历史记录代替
- forward()、back() 返回历史记录的上一条或下一条地址
- go(n) 根据n的正负来决定是回退或者是前进几条历史记录。
- 我们给三级路由再加按钮,实现跟左边同样功能。
<ul>
<li v-for="(value, index) in peoples" :key="index">
<!-- to采用对象传参的形式,使传递的信息更丰富 ,query中储存要传递的数据 -->
<router-link replace active-class="active" :to="{
name: 'endpath',
params:{
zong: infos[index]
}
}">{{ value }}</router-link>
<!-- 声明编程式导航的标签触发,value是将for出来的value值传入参数 -->
<button @click="changeCom(index)">用push</button>
</li>
<router-view></router-view>
</ul>
methods:{
changeCom(index){
this.$router.push({
name:"endpath",
params:{
zong:this.infos[index],
}
})
}
}
(十一)保持路由组件挂载
- 当我们某些组件中需要输入信息,我们不希望组件被切走后自动给执行销毁流程,就需要让组件保持挂载
- 方法:
再路由展示位置加上<keepAlive name="组件名"> 将<router-view>放入,即可保持该组件的持续挂载
再Two组件中有加了路由,过程忽略
展示Two结构
<div>
<div>我是Two组件中的内容</div>
<hr>
<!-- 注意嵌套的二级路由需要写出完整路径 -->
<router-link replace active-class="active" to="/two/twoone">动漫人物列表</router-link>
<router-link active-class="active" to="/two/twotwo">一些胡思乱想</router-link>
<router-link to="/two/threeinput">显示输入框</router-link>
<KeepAlive name="Input">
<router-view></router-view>
</KeepAlive>
</div>
如果想保留多个挂载,用include代替name
<KeepAlive :inclued="['name1','name2']">
<router-view></router-view>
</KeepAlive>
效果实现。
(十二)路由组件独有的两个钩子(生命周期函数)
- deactivated()当组件失活时,函数被触发,组件失活和挂载不冲突,失活就是不在界面展示了
- activated() 当组件激活时函数被触发。
(十三)关于路由组件的注意点
- 被路由的组件一般放在跟components同级的pages文件夹下。
- 被路由的组件不会显式出现在其他组件结构中,被路由器控制显示
- 每个被路由的组件都会多出两个属性:router和route,分别储存路由路径等信息,和路由器
- 不同路由组件的router是一个,即所有被路由的组件,都可以调用同一个路由器。
二十九、全局路由守卫
(一)路由组件被路由的过程:
(二)路由时传给Router的对象结构
A、路由时,路由者将自己的router传给router同时将数据和目标地址传给router,下面展示route的结构:
- query、params携带的是要传递的数据。
- name是在router给该组件定义的名字
- meta 中可以自定义一些数据再组件挂载前和挂载后使用。
B、路由器收到该路由请求后,会根据to中路径指向(或name指向)将目标的route找出,一起和发起路由组件的route,传给前置和后置守卫方法的回调函数参数中。
C、路由器将数据和方向确定之后,就先将两个组件的route信息交给前置守卫,一起被传递的还有放行函数。
- 在前置守卫中我们可以进行组件挂载之前的鉴权(根据cookie信息,核实调用人身份)。
D、下面我们要处理前置守卫中的逻辑信息,进行鉴权
- 前置守卫声明的方式如下(index.js中,即路由器)
-
//引入vue-router import VueRouter from "vue-router"; //引入需要用到的路由组件 //......... //设置前置守卫的第一步是取消本来创建好路由器直接暴露的行为 //第一步,我们把路由器赋值给vueRouter变量 const vueRouter = new VueRouter({ routes:[ //具体的路由细节 ] }); //第二步,调用路由器实例的beforeEach方法,传入回调函数 //配置前置路由守卫,传入的回调函数会被传入三个参数, //第一个to里面是要挂载的组件的$route,第二个from是路由发起的组件的$route //next是放行挂载的方法。 vueRouter.beforeEach((to,from,next)=>{ }); //声明后置守卫的位置 //如果没有后置守卫,那就把路由器暴露出去,让下一步逻辑继续执行 export default vueRouter;
- 在前置守卫中处理鉴权逻辑
在鉴权前先准备鉴权条件,模拟用户登陆的cookie
然后处理逻辑如下:
vueRouter.beforeEach((to,from,next)=>{
//判断用户cookie确定是否放行
if(document.cookie == "namecool=chenshaoxia"){
//如果cookie对上了,输出目标的路径,并就放行
console.log("被前置守卫放行,路径是"+to.path);
next();
}else{
alert("抱歉,您权限不足无法路由");
}
});
这样我们就把所有路由都加上了守卫,只有固定用户才能实现跳转,这里我们修改cookie,进行跳转尝试,发现失败
E、假设改权限足够,进入组件挂载阶段,后调用后置守卫
- 后置守卫能干什么?
例子:能够在组件挂载后更改网页页签内容
- 后置守卫的声明
vueRouter.afterEach((to,from)=>{
//修改网页的标签名
//首先获取组件名,然后判断是否为该组件,如果是就更改页签名。
if(to.path == "/two" ){
document.title = "热火";
}
})
跟前置守卫相比,后置守卫的回调函数少了next参数,因为是后置守卫,就不需要再给谁放行,就是一个兜底的方法。
D、最后加上meta的使用。
{
path:"/one",
component: One,
meta:{
cool: "namecool=chenshaoxia"
}
},
三十、独享路由守卫和路由进入守卫(内容守卫)
(一)新的守卫流程
(二)独享前置守卫(没有独享后置守卫)
- 在路由器中的配置规则内部直接声明,以/one路由为例
{
path:"/one",
component: One,
meta:{
cool: "namecool=chenshaoxia"
},
//声明独享守卫
beforeEnter(to,from,next){
console.log("/one的独享守卫得到了执行");
//放行
next();
}
},
(三)内容路由进入前守卫和内容路由离开前守卫
这两个守卫是声明在组件内部的;
- 声明格式
export default {
name:"One",
//声明内容路由进入前守卫
beforeRouteEnter(to,from,next){
console.log("这里我们进入了one组件");
next();
},
//声明内容路由离开守卫
beforeRouteLeave(to,from,next){
console.log("这里我们从one组件出去了");
next();
},
}
三十一、vue路由的两种模式(history和默认模式)
- 两种模式的区别:
- 默认模式,会在我们路由的路径前加上#来表示下面的路径都是hash值,不会经过服务器
- history,所有的路径都会变为默认路径,向服务器请求,这些就需要后端来解决了。
- 声明方式在路由器中声明,跟routes同级。