L o a d i n g . . .
SHIWIVI-文章

//sunny forever
while(life<end){
love++;
beAwesome :)}

    <
  • 主题:
  • + -
  • 清除背景
  • 禁用背景

路由与路由守卫

字数:16522 写于:2022-07-16
最新更新:2022-07-16 阅读本文预计花费您48分钟
vue路由官方网站:https://router.vuejs.org/zh/

入门

介绍

  • Vue Router 是Vue的官方路由插件,用于构建单页应用
  • 页面不刷新,配合ajax实现页面的局部更新,并响应式更新地址栏URL
  • 在工程中,普通组件一般放在components下,而路由组件放于pages目录下
  • 切换组件时,未调用的组件是被销毁的,调用时被挂载
  • 整个应用由一个router(路由器)统一管理,通过$router调用
  • 但每个路由组件都有自己的$route属性

安装vue router

vue2的工程使用vue-router3,vue3的工程使用vue-router4,版本需要对应,这里以安装vue-router3为例

在脚手架中执行:

npm i vue-router@3

路由的使用

案例:通过组件嵌套,实现功能

  1. 在app单个页面中通过按钮实现Home和About页面的切换
  2. About页面中嵌套aboutMe和aboutWeb页面

1. 新建pages目录,存放Home.vue、About.vue、aboutMe、aboutWeb组件

Home.vue文件:

<template>
  <div class="home">
    <h2>Home页面</h2>
  </div>
</template>
<script>
export default {
    name:'pageHome'
  }
</script>

About.vue文件:

<template>
  <div class="about">
    <h2>About页面</h2>
    <div class="about-btn">
    <!--router-link标签路由切换按钮的两种写法,该标签最后会被解析为a标签-->
    <!--1. 根据路径调用组件-->
    <router-link to="/about/aboutWeb">关于网页</router-link> 
    <router-link to="/about/aboutMe">关于我</router-link> 
    <!--2. 根据路由规则中的name属性调用组件-->
    <router-link :to="{name: 'aboutme'}">关于网页</router-link> 
    <router-link :to="{name: 'aboutweb'}">关于我</router-link> 
    </div>
    <div class="about-content">
    <!--子组件显示的位置-->
    <router-view></router-view> 
    </div>
  </div>
</template>
 <script>
 export default {
     name:'pageAbout'
 }
</script>

aboutWeb.vue文件 (aboutMe.vue类似)

<template>
  <div>
    <ul>
        <li v-for="(t,index) in tech" :key="index">{{t}}</li>
    </ul>
  </div>
</template>

<script>
 export default {
    name:'aboutWeb',
    data(){
        return{
            tech:{
                前端:'html/css/javaScript',
                后端:'java',
                系统:'CentOS7',
                服务器:'nginx'
            }
        }
    }
 }
</script>

2. 新建router目录,新建index.js文件用于创建路由器
index.js文件:

// 引入vueRouter插件
import VueRouter from "vue-router";
//引入路由组件
import Home from '../pages/pageHome'
import About from '../pages/pageAbout'
import aboutMe from '../pages/aboutMe'
import aboutWeb from '../pages/aboutWeb'
// 创建路由器
export default new VueRouter({
    // 创建路由规则一个{}内为一条路由
    routes:[
        {
            name: 'home',    //路由规则指定的组件别名
            path:'/home',   //路由路径
            component:Home //调用的组件
        },
        {   
            name: 'about',
            path:'/about',
            component:About,
            children:[     //组件嵌套
                {   
                    name:'aboutme',
                    path:'aboutMe',
                    component:aboutMe
                },
                {   
                    name:'aboutweb',
                    path:'aboutWeb',
                    component:aboutWeb
                }
            ]
        }
    ]
 })

3. 在main.js中引入路由器

import Vue from 'vue'
import App from './App.vue'
// 引入vue-router
import VueRouter from 'vue-router'
// 使用vue-router
Vue.use(VueRouter)
// 引入创建的路由器
import router from './router'
new Vue({
  render: h => h(App),
  router:router   //配置路由器
}).$mount('#app')

4. 在App中调用路由组件

<template>
  <div id="app">
    <div class="btn">
      <!-- active-class用于指定该链接按钮被选中时生效的样式-->
      <router-link class="link" active-class="active" to="/home">Home</router-link>
      <router-link class="link" active-class="active" to="/about">About</router-link>
      <!-- 同样,to可以写为对象形式 -->
      <router-link class="link" active-class="active" :to="{name:'home'}">Home</router-link>
      <router-link class="link" active-class="active" :to="{name:'about'}">About</router-link>
    </div>
    <div class="content">
      <!-- 指定组件显示的位置 -->
      <router-view></router-view>
    </div>
  </div>
</template>
<script>
 export default {
  name:'App',
 }
</script>

路由传参

query传参

父组件可通过向 to 属性添加参数进行传参,类似于带参数的http请求,子路由可通过$route.query.参数名读取数据

案例:为aboutWeb组件添加子组件webTech,并由aboutWeb向webTech传参

方法1:通过字符串传参

在路由路径后添加查询字符串 ? ,并在之后以键值对的方式传参。

父组件 aboutWeb.vue

<template>
  <div>
    <ul>
        <li v-for="(t,index) in tech" :key="index">
        <!-- 字符串写法 -->
        <!-- 注意:由于to前使用了:解析js语法,因此要添加``将语句解析为字符串 -->
        <router-link :to="`/about/aboutWeb/webTech?name=${t.name}&lang=${t.language}`">{{t.name}}</router-link>
        </li>
    </ul>
    <router-view></router-view>
  </div>
</template>
<script>
 export default {
    name:'aboutWeb',
    data(){
        return{
            tech:[
                {name:'前端',language:'html/css/javaScript'},
                {name:'框架',language:'vue'},
                {name:'后端',language:'java'},
                {name:'系统',language:'CentOS7'},
                {name:'服务器',language:'nginx'},
                ]
            }
        }
 }
</script>
方法2:通过对象传参
<template>
  <div>
    <ul>
        <li v-for="(t,index) in tech" :key="index">
        <!-- 对象写法 -->
            <router-link :to="{
            path:'/about/aboutWeb/webTech',
            query:{
                name:t.name,
                lang:t.language
            }
            }">
            {{t.name}}
            </router-link>
        </li>
    </ul>
    <router-view></router-view>
  </div>
</template>
<script>
 export default {
    name:'aboutWeb',
    data(){
        return{
            tech:[
                {name:'前端',language:'html/css/javaScript'},
                {name:'框架',language:'vue'},
                {name:'后端',language:'java'},
                {name:'系统',language:'CentOS7'},
                {name:'服务器',language:'nginx'},
                ]
            }
        }
 }
</script>
子路由读取参数

webTech.vue文件:

<template>
  <div class="show">
  <!-- 读取数据 -->
    <span class="tech-name">{{$route.query.name}}:</span>
    <span class="tech-lang">{{$route.query.lang}}</span>
  </div>
</template>

<script>
 export default {
    name:'webTech'
 }
</script>

params传参

方法1:通过字符串传参

通过字符串传参时,必须在配置路由规则时在path路径中指定解析的参数

 {   
  name:'aboutweb',
  path:'aboutWeb',
  component:aboutWeb,
  children:[{
    path:'webTech/:name/:lang', //在路径中解析参数
    conpontent:webTech
  }]
      }

父组件通过附带参数的路径传输参数

<router-link :to="`/about/aboutWeb/webTech?name=${t.name}&lang=${t.language}`">{{t.name}}</router-link>

子组件通过$route.params.参数名读取参数

<span class="tech-name">{{$route.params.name}}</span>
<span class="tech-lang">{{$route.params.lang}}</span>
方法2:通过对象传参

通过对象传参时,to属性不能再使用path调用组件,而需要使用name属性,因此路由规则中一定需要给予组件name属性

{   
  name:'aboutweb',
  path:'aboutWeb',
  component:aboutWeb,
  children:[{
    name:'webtech' //必须
    path:'webTech/:name/:lang', //必须
    conpontent:webTech
  }]
      }

传参的父组件

<router-link :to="{
            name:'webtech', //不能使用path
            params:{
                name:t.name,
                lang:t.language
            }}">
            {{t.name}}
</router-link>

子组件通过$route.params.参数名读取参数,代码同上

props属性

当需要大量调用参数时,频繁使用$route.query增加了代码量,可以在路由中配置props属性简化代码。props属性支持三种配置方法。

1. 对象形式,传输固定参数
{   
  name:'aboutweb',
  path:'aboutWeb',
  component:aboutWeb,
  children:[{
    name:'webtech' 
    path:'webTech',
    conpontent:webTech,
    //对象形式,传输固定参数
    props:{ name:'框架',
            lang:'Vue'}
  }]
      }
2. 函数形式,传输指定参数(用query)
{   
  name:'aboutweb',
  path:'aboutWeb',
  component:aboutWeb,
  children:[{
    name:'webtech' 
    path:'webTech',
    conpontent:webTech,
    //对象形式,传输固定参数
    pros(route){
      return {
        name: route.query.name,
        lang: route.query.language
      }
    }
  }]
      }
3. 布尔值,自动传输所有params参数
{   
  name:'aboutweb',
  path:'aboutWeb',
  component:aboutWeb,
  children:[{
    name:'webtech' 
    path:'webTech/:name/:lang', //自动传输所有参数
    conpontent:webTech,
    //布尔值形式
    pros: true
  }]
      }
接收参数

子组件需要通过props属性接收参数

<span>{{name}}</span> //直接调用
<span>{{lang}}</span>
export default{
   name:'webTech',
  pros:['name','lang'] //接收参数
   }

路由导航

路由导航分为声明式和编程式

  • 声明式:通过<router-link>配置to属性实现跳转
  • 编程式:通过调用push、back等API跳转组件

路由导航与浏览器历史记录

浏览器历史记录默认为push状态,组件的跳转会记录到历史记录中,通过浏览器的前进/后退按钮,或者调用goback等API,能根据历史记录实现页面的前进、回退。当浏览器历史记录切换为replace状态时,浏览器会使用当前页面的记录替换掉上一条历史记录。

 <--跳转到About页面后,About页面的历史记录会替换掉该页的历史记录,此时无法再使用浏览器的回退按钮返回该页面了-->
<router-link replace to="...">跳转到About页面</router-link>

编程式路由导航

不借助<router-link>标签,实现路由跳转
API:

  • push:跳转到指定路由组件
  • replace:跳转到指定路由组件并替换浏览器历史记录
  • back:回退
  • forward:前进(需要之前回退过)
  • go(值):根据值前进/回退指定次数

eg:通过按钮实现(或div)实现路由跳转

<template>
  <div>
   <button class="link" @click="backTo">回退</button>
    <button class="link" @click="forwardTo">前进</button>
    <button class="link" @click="goTo">跳转</button>
    <ul>
        <li v-for="(t,index) in tech" :key="index">
            <button @click="pushTo(t)">push</button>
            <button @click="replaceTo(t)">replace</button>
        </li>
    </ul>
    <router-view></router-view>
  </div>
</template>

<script>
 export default {
    name:'aboutWeb',
    data(){
        return{
            tech:[
                {name:'前端',language:'html/css/javaScript'},
                {name:'后端',language:'java'},
                {name:'系统',language:'CentOS7'},
                {name:'服务器',language:'nginx'},
                ]
            }
        },
    methods:{
        backTo(){
      this.$router.back() //回退一次
    },
    forwardTo(){
      this.$router.forward() //前进一次
    },
    goTo(){
      this.$router.go(-2) //,回退2步,正数前进,负数后退
    },
        pushTo(m){    //跳转到指定组件
            this.$router.push({
                path:'/about/aboutWeb/webTech',
                query:{
                name:m.name,
                lang:m.language
            }
            })
        },
        replaceTo(n){  //跳转到指定组件并替换上一个历史记录
            this.$router.replace({
                path:'/about/aboutWeb/webTech',
                query:{
                name:n.name,
                lang:n.language
            }
            })
        }
    }
 }
</script>

路由组件的缓存

当组件进行切换时,原组件会被销毁,原组件中未保存的表单内容等数据同时也会被删除,此时,可以使用<keep-alive>标签阻止组件被销毁,保留数据。

 //缓存多组件使用 :include="['组件1','组件2',...]"
<keep-alive include="aboutMe"> 
  <router-view></router-view>
</keep-alive>

路由独有生命周期

  • activated:当组件被激活时(显示到页面)
  • deactivated:当组件失活时
    当组件被<keep-alive>时,组件不会被销毁,在切换组件时created、destory等钩子函数不会执行,此时可以使用activated、deactivated替代。

eg:使某组件在激活时启用定时器,失活时关闭

 export default {
  name:'webTech',
  data(){.....},
  activated(){
            let timer=setInterval(....);
            },
  deactivated(){
            clearInterval(this.timer)
            }
 }

路由守卫

在切换组件时,可借助路由守卫来阻止/放行组件的跳转,常用于判断用户是否有权限访问,无权限时阻止访问,也可用于在组件跳转前后执行某些功能。

前置、后置路由守卫(全局)

该路由守卫写于路由器配置文件中

  • beforeEach((to,from,next)=>{ }):前置路由守卫,在初始化、路由跳转前执行,接收to,from,next三个参数,to代表即将跳转的组件,from为来源组件,next代表放行
  • beforeEach((to,from)=>{ }):后置路由守卫,在路由跳转后执行,接收to,from两个参数

eg: 检查用户是否为指定用户,不是则禁止访问aboutWeb和aboutMe组件

 import VueRouter from "vue-router";
 import Home from '../pages/pageHome'
 import About from '../pages/pageAbout'
 import aboutMe from '../pages/aboutMe'
 import aboutWeb from '../pages/aboutWeb'
 import webTech from '../pages/webTech'
 const router= new VueRouter({
    routes:[
        {
            name:'home',
            path:'/home',   
            component:Home, 
            meta:{title:'首页'}//meta为自定义属性,程序员可自定义添加任何参数
        },
        {
            name:'about',
            path:'/about',
            component:About,
            meta:{title:'关于'},
            children:[
                {
                    name:'aboutme',
                    path:'aboutMe',
                    component:aboutMe,
                    meta:{isAuth:true,//标识该组件是否需要鉴别权限
                          title:'关于我'}//用于组件跳转后修改地址栏标题
                },
                {
                    name:'aboutweb',
                    path:'aboutWeb',
                    component:aboutWeb,
                    meta:{isAuth:true,
                        title:'关于网站'},
                    children:[
                        {
                            name:'webTech',
                            path:'webTech',
                            component:webTech,
                            meta:{title:'关于本站采用的技术'}
                        }
                    ]
                }
            ]
        }
    ]
 })
// 全局前置路由守卫
 router.beforeEach((to,from,next)=>{
        if(to.meta.isAuth){//确认是否鉴权,避免对所有组件都进行鉴权消耗性能
 // 当组件不多时,可以使用下面的代码通过判断路径来识别哪些组件需要权限认证
        // if(to.name==='aboutme'||to.path==='/about/aboutWeb')
        //只有localStorage中的user为zhoujielun才能访问
            if(localStorage.getItem('user')==='zhoujielun'){
                next() //放行访问
            }
            else{
                alert('无权限访问')
            }
        }
        else{
            next()  //对不需要权限认证的页面直接放行
        } 
 })
// 全局后置路由守卫
//用于切换完毕后,修改网页地址栏的标题
 router.afterEach((to)=>{
    document.title=to.meta.title  
 })
 export default router

独享路由守卫

只为某个路由组件配置的路由守卫, 同样写于路由器配置文件中
beforeEnter:(to,from,next)=>{ }只对针对某个组件配置守卫,同样接收to,from,next三个参数,to代表即将跳转的组件,from为来源组件,next代表放行

eg: 判断用户是否为指定用户,不是则禁止访问aboutMe组件

{
            name:'about',
            path:'/about',
            component:About,
            meta:{title:'关于'},
            children:[
                {
                    name:'aboutme',
                    path:'aboutMe',
                    component:aboutMe,
                    meta:{isAuth:true,//鉴别权限
                          title:'关于我'},
                          //独享路由守卫
                          beforeEnter:(to,from,next)=>{
                                if(to.meta.isAuth){
                                  //只有localStorage中的user为zhoujielun才能访问
                                    if(localStorage.getItem('user')==='zhoujielun'){
                                        next()
                                    }
                                    else{
                                        alert('无权限访问')
                                    }
                                }
                                else{
                                    next()
                                } 
                          }
                },

组件内路由守卫

无法修改路由器配置文件时,可以将路由守卫设于组件.vue的文件中。组件内的路由守卫只会在通过路由规则进入组件时才会执行,如果将组件标签直接添加到页面中,该组件会被调用,但此时不属于通过路由规则进入组件,不会执行下述路由守卫函数。

  • beforeRouteEnter(to,from,next){ }:进入组件前执行
  • beforeRouteLeave(to,from,next){ }:离开组件前执行
  • beforeRouteUpdate(to,from,next){ }:组件更新时执行
<template>
  <div class="about">
    <h2>About页面</h2>
    <div class="about-btn">
    <router-link  to="/about/aboutWeb">关于网页</router-link>
    <router-link  to="/about/aboutMe">关于我</router-link>
    </div>
    <div class="about-content">
      <keep-alive include="aboutMe">
      <router-view></router-view>
      </keep-alive>
    </div>
  </div>
 </template>
 <script>
 export default {
    name:'pageAbout',
    // 通过路由规则进入组件时调用
    beforeRouteEnter(to,from,next){
      //只有localStorage中的user为zhoujielun才能访问
            if(localStorage.getItem('user')==='zhoujielun'){
                    next()
                    }
            else{
                 alert('无权限访问')
             }
    },
     // 通过路由规则离开组件时调用
    beforeRouteLeave(to,from,next){
      console.log('即将离开组件')
        next();//放行
    }
}
 </script>
上一篇:基于certbot获取TLS证书
下一篇:yaml语法
z z z z z