Vue2路由的基本知识

162 阅读11分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

路由理解

路由

1.一组路由就是一组key-value的映射关系。

2.key为路径,value可能是函数和组件。

路由分类

路由分为前端路由和后端路由。

前端路由:

1.value为组件,展示相关组件内容。

2.当浏览器的路径改变时,对应的组件就会显示。

后端路由:

1.value为函数,用于处理客户端提出的请求。

2.服务器接收一个请求时,会根据请求路径找到匹配的函数来处理相关请求,返回响应数据。

下载路由插件vue-router

vue-router是vue的一个插件库,专门用来实现SPA(单页面Web应用)。

下载插件:

现在默认的是4版本,vue-router 4只能在vue3中使用,而vue-router 3,可以在vue2中使用。

npm install vue-router@3 --save-dev  

因为路由是展示组件相关内容,所以写了两个组件StudentList和SchoolList;

在项目src目录下创建router目录,在router目录下创建index.js文件。

并写一些基础配置

路由文件index.js

// 该文件用于创建整个应用的路由器

// 引入Vue
import Vue from "vue";
// 引入路由插件
import VueRouter from "vue-router";
// 引入组件
import StudentList from '@/components/StudentList'
import SchoolList from '@/components/SchoolList'

//使用插件
Vue.use(VueRouter);

// 创建一个路由器并暴露出去
export default new VueRouter({
    //全部路由
    routes: [
        {
            path: '/student',
            component: StudentList
        },
        {
            path: '/school',
            component: SchoolList
        }
    ]

})

在main.js中配置路由文件

import Vue from 'vue'
import App from './App.vue'
import VueLazyLoad from 'vue-lazyload'
// 引入路由文件
import router from '@/router/index'

Vue.config.productionTip = false
// Vue.use(VueLazyLoad)

Vue.use(VueLazyLoad, {
  preLoad: 1.3,
  error: require('./assets/img/logo.png'),
  loading: require('./assets/img/logo.png'),
  attempt: 1
  })

new Vue({
  // 配置router
  router,
  render: h => h(App),
}).$mount('#app')

路由就配置成功了。

less和less-loader插件安装

这里由于CSS样式使用less,所以需要安装less 和less-loader插件。

注意版本问题,否则运行项目会报错。在vue2中使用以下版本不会报错。

npm install less@3.9.0 -s
npm install less-loader@5.0.0 -s

router-link

路由导航,实现切换。

App.vue中添加:

<router-link class="link-show" active-class="active" to="/student">学生列表</router-link>
      
<router-link class="link-show" active-class="active" to="/school">学校列表</router-link>

to跳转的地址就是在路由文件里面配置的path,router-link相当于一个a标签,如果想改变其类型,可添加tag属性,如改成按钮:

<router-link class="link-show" tag="button" active-class="active" to="/student">学生列表</router-link>
      
<router-link class="link-show" tag="button" active-class="active" to="/school">学校列表</router-link>

router-view

路由视图,指定展示位置。

App.vue中添加:

<router-view></router-view>

App.vue完整代码:

<template>
  <div id="app">
    <!-- 路由导航,实现切换 -->
    <div>
      <router-link class="link-show" active-class="active" to="/student">学生列表</router-link>
      <router-link class="link-show" active-class="active" to="/school">学校列表</router-link>
    </div>
    <!-- 路由视图,指定展示位置 -->
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App',
  components: {

  }
}
</script>

<style lang="less">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
  .active{
    background: #2866f9;
    border-radius: 2px;
  }
  .link-show{
    display: inline-block;
    border: 1px solid;
    width: 100px;
    height: 20px;
    text-decoration: none;
  }
}
</style>

点击切换,会显示相应组件的内容。

image.png

image.png

通过切换,隐藏的路由组件是被销毁了,需要时再挂在。

每个组件都有自己的$route属性,里面存储自己的路由信息。

整个应用只有一个$router。

一个基础的路由切换就完成了,是根据路由规则去匹配相关路由。当然,如果是完整的一个项目,在路由文件中就会有很多其他的设置。

路由文件基础配置

这里主要介绍了嵌套路由、路由模式。

嵌套路由(多级路由)

嵌套路由又称子路由、多级路由,在实际应用中,通常由多层嵌套的组件组合而成。

这里是给学校组件加子路由ClassInfo和TeacherInfo组件。

首先,需要在路由文件中把路由规则写好。

路由文件index.js

// 该文件用于创建整个应用的路由器

// 引入Vue
import Vue from "vue";
// 引入路由插件
import VueRouter from "vue-router";
// 引入组件
import StudentList from '@/components/StudentList'
import SchoolList from '@/components/SchoolList'
import ClassInfo from '@/components/ClassInfo'
import TeacherInfo from '@/components/TeacherInfo'

//使用插件
Vue.use(VueRouter);

// 创建一个路由器并暴露出去
export default new VueRouter({
    //全部路由
    routes: [
        {
            path: '/student',
            component: StudentList
        },
        {
            path: '/school',
            component: SchoolList,
            // 通过设置children配置子级路由
            children:[
                {
                    path: 'class', // 不要写成/class
                    component: ClassInfo
                },
                {
                    path: 'teacher',// 不要写成/teacher
                    component: TeacherInfo,
                }
            ]
        }
    ]

})

然后,再去学校组件配置:

SchoolList.vue

<template>
    <div class="school-info">
        这是学校组件
        <div>
            <router-link class="link-show" active-class="active" to="/school/class">班级信息</router-link>
            <router-link class="link-show" active-class="active" to="/school/teacher">老师信息</router-link>
        </div>
        <router-view></router-view>
    </div>
</template>

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

<style  lang="less">
.school-info{
    .link-show{
        display: inline-block;
        border: 1px solid;
        width: 100px;
        height: 20px;
        text-decoration: none;
    }
}
</style>

注意,router-link里面的to是要从第一级写,要写完整路径,即/school/class。

选择学生列表,展示学生组件的内容:

image.png

选择学校列表,班级信息路由和老师信息路由就展示出来了:

image.png

选择班级信息,展示班级组件的内容:

image.png

选择老师信息,展示老师组件的内容:

image.png

路由模式

vue的路由模式分为hash和history,默认为hash模式。

在访问上面的vue项目时,我们观察访问地址,可以看见地址里面带有一个#号:

image.png

从#开始的所有东西,都叫url的hash值。hash值的特点就是不会随着http请求发给服务器,即不会作为请求资源传给服务器。

默认为hash模式,如果想要用history模式,则需要在路由文件中配置mode选项:

路由文件index.js

// 该文件用于创建整个应用的路由器

// 引入Vue
import Vue from "vue";
// 引入路由插件
import VueRouter from "vue-router";
// 引入组件
import StudentList from '@/components/StudentList'
import SchoolList from '@/components/SchoolList'
import ClassInfo from '@/components/ClassInfo'
import TeacherInfo from '@/components/TeacherInfo'

//使用插件
Vue.use(VueRouter);

// 创建一个路由器并暴露出去
export default new VueRouter({
    // 设置路由模式
    mode:'history',
    //全部路由
    routes: [
        {
            path: '/student',
            component: StudentList
        },
        {
            path: '/school',
            component: SchoolList,
            // 通过设置children配置子级路由
            children:[
                {
                    path: 'class', // 不要写成/class
                    component: ClassInfo
                },
                {
                    path: 'teacher',// 不要写成/teacher
                    component: TeacherInfo,
                }
            ]
        }
    ]

})

此时访问时,就没有#:

image.png

比较:

hash模式: 1.地址中有#。 2.若将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。 3.兼容性较好。

history模式: 1.地址中没有#。 2.兼容性相比于hash模式较差。 3.应用部署上线时需要nginx代理或者后端人员处理,解决刷新页面服务端404的问题。

路由传参-query

1.跳转路由时携带参数,使用to的字符串写法,因为参数是动态的,所以需要动态绑定to。

<router-link class="link-show" active-class="active" :to="`/school/teacher?id=${id}&name=${name}`">老师信息</router-link>

2.跳转路由时携带参数,使用to的对象写法。

<router-link class="link-show" active-class="active" 
                    :to="{
                        path:'/school/teacher',
                        query: {
                            id:id,
                            name:name
                        }
                    }">
            老师信息
            </router-link>

使用query传参,不会影响路由文件配置index.js。

teacher组件接收参数:

$route.query.id
$route.query.name

路由传参-params

使用params传参,使用to的字符串写法。

<router-link class="link-show" active-class="active" :to="`/school/teacher/${id}/${name}`">老师信息</router-link>

需要去路由文件中设置占位符,不然参数就会被路由层级。

路由文件index.js

// 该文件用于创建整个应用的路由器

// 引入Vue
import Vue from "vue";
// 引入路由插件
import VueRouter from "vue-router";
// 引入组件
import StudentList from '@/components/StudentList'
import SchoolList from '@/components/SchoolList'
import ClassInfo from '@/components/ClassInfo'
import TeacherInfo from '@/components/TeacherInfo'

//使用插件
Vue.use(VueRouter);

// 创建一个路由器并暴露出去
export default new VueRouter({
    // 设置路由模式
    mode:'history',
    //全部路由
    routes: [
        {
            name: 'student', //名字自定义,不受其他参数影响。
            path: '/student',
            component: StudentList
        },
        {
            name: 'school',
            path: '/school',
            component: SchoolList,
            // 通过设置children配置子级路由
            children:[
                {
                    name: 'class',
                    path: 'class', // 不要写成/class
                    component: ClassInfo
                },
                {
                    name: 'teacher',
                    // params传参,使用占位符声明接收参数
                    path: 'teacher/:id/:name',// 不要写成/teacher
                    component: TeacherInfo,
                }
            ]
        }
    ]

})

使用params传参,使用to的对象写法。

<router-link class="link-show" active-class="active" 
                    :to="{
                        name:'teacher',
                        params: {
                            id:id,
                            name:name
                        }
                    }">
            老师信息
            </router-link>

注意:路由携带params参数时,若使用to的对象写法,则必须使用name配置。

使用query传参,需要在路由文件配置index.js相应路由上使用占位符声明接收参数。

teacher组件接收参数:

$route.params.id
$route.params.name

路由的命名空间

路由文件index.js

// 该文件用于创建整个应用的路由器

// 引入Vue
import Vue from "vue";
// 引入路由插件
import VueRouter from "vue-router";
// 引入组件
import StudentList from '@/components/StudentList'
import SchoolList from '@/components/SchoolList'
import ClassInfo from '@/components/ClassInfo'
import TeacherInfo from '@/components/TeacherInfo'

//使用插件
Vue.use(VueRouter);

// 创建一个路由器并暴露出去
export default new VueRouter({
    // 设置路由模式
    mode:'history',
    //全部路由
    routes: [
        {
            name: 'student', //名字自定义,不受其他参数影响。
            path: '/student',
            component: StudentList
        },
        {
            name: 'school',
            path: '/school',
            component: SchoolList,
            // 通过设置children配置子级路由
            children:[
                {
                    name: 'class',
                    path: 'class', // 不要写成/class
                    component: ClassInfo
                },
                {
                    name: 'teacher',
                    path: 'teacher',// 不要写成/teacher
                    component: TeacherInfo,
                }
            ]
        }
    ]

})

使用命名时,在路由跳转或带参数跳转时可以简化一些代码。

 <router-link class="link-show" active-class="active" to="/school/teacher">老师信息</router-link>

换成

<router-link class="link-show" active-class="active" :to="{name:'teacher'}">老师信息</router-link>

带参数跳转时,使用name。

<router-link class="link-show" active-class="active" 
                    :to="{
                        name:'teacher',
                        query: {
                            id:id,
                            name:name
                        }
                    }">
            老师信息
            </router-link>

路由传参-props

使用props读取参数简单,不用route.query.nameroute.query.name或route.params.name。

这里对teacher组件的路由进行props设置。

props的值为对象

路由文件index.js

// 该文件用于创建整个应用的路由器

// 引入Vue
import Vue from "vue";
// 引入路由插件
import VueRouter from "vue-router";
// 引入组件
import StudentList from '@/components/StudentList'
import SchoolList from '@/components/SchoolList'
import ClassInfo from '@/components/ClassInfo'
import TeacherInfo from '@/components/TeacherInfo'

//使用插件
Vue.use(VueRouter);

// 创建一个路由器并暴露出去
export default new VueRouter({
    // 设置路由模式
    mode:'history',
    //全部路由
    routes: [
        {
            name: 'student', //名字自定义,不受其他参数影响。
            path: '/student',
            component: StudentList
        },
        {
            name: 'school',
            path: '/school',
            component: SchoolList,
            // 通过设置children配置子级路由
            children:[
                {
                    name: 'class',
                    path: 'class', // 不要写成/class
                    component: ClassInfo
                },
                {
                    name: 'teacher',
                    // params传参
                    path: 'teacher',// 不要写成/teacher
                    component: TeacherInfo,
                    // props第一种写法,值为对象,对象里面的所有key-value都会以props的形式传给teacher组件。
                    props:{id:1,name:'props对象写法'}
                }
            ]
        }
    ]

})

参数接受,则直接props接收。

teacher组件

<template>
    <div>
        这是学校里面老师的信息+{{this.id}}+{{this.name}}
    </div>
</template>

<script>
export default {
    name: 'TeacherInfo',
    props:['id','name']
}
</script>

<style  lang="less">

</style>

image.png

props的值布尔值

路由文件index.js

// 该文件用于创建整个应用的路由器

// 引入Vue
import Vue from "vue";
// 引入路由插件
import VueRouter from "vue-router";
// 引入组件
import StudentList from '@/components/StudentList'
import SchoolList from '@/components/SchoolList'
import ClassInfo from '@/components/ClassInfo'
import TeacherInfo from '@/components/TeacherInfo'

//使用插件
Vue.use(VueRouter);

// 创建一个路由器并暴露出去
export default new VueRouter({
    // 设置路由模式
    mode:'history',
    //全部路由
    routes: [
        {
            name: 'student', //名字自定义,不受其他参数影响。
            path: '/student',
            component: StudentList
        },
        {
            name: 'school',
            path: '/school',
            component: SchoolList,
            // 通过设置children配置子级路由
            children:[
                {
                    name: 'class',
                    path: 'class', // 不要写成/class
                    component: ClassInfo
                },
                {
                    name: 'teacher',
                    // params传参
                    path: 'teacher/:id/:name',// 不要写成/teacher
                    component: TeacherInfo,
                    // props第二种写法,值为布尔值,若布尔值为真就会把该路由组件收到的所有params参数以props的形式传给teacher组件。
                    props: true
                }
            ]
        }
    ]

})

teacher组件

<template>
    <div>
        这是学校里面老师的信息+{{this.id}}+{{this.name}}
    </div>
</template>

<script>
export default {
    name: 'TeacherInfo',
    props:['id','name']
}
</script>

<style  lang="less">

</style>

image.png

props的值为函数

第二种方法是params传参才能使用,这种方法能够使用$route,params传参和query传参都能传递参数到组件。

路由文件index.js

// 该文件用于创建整个应用的路由器

// 引入Vue
import Vue from "vue";
// 引入路由插件
import VueRouter from "vue-router";
// 引入组件
import StudentList from '@/components/StudentList'
import SchoolList from '@/components/SchoolList'
import ClassInfo from '@/components/ClassInfo'
import TeacherInfo from '@/components/TeacherInfo'

//使用插件
Vue.use(VueRouter);

// 创建一个路由器并暴露出去
export default new VueRouter({
    // 设置路由模式
    mode:'history',
    //全部路由
    routes: [
        {
            name: 'student', //名字自定义,不受其他参数影响。
            path: '/student',
            component: StudentList
        },
        {
            name: 'school',
            path: '/school',
            component: SchoolList,
            // 通过设置children配置子级路由
            children:[
                {
                    name: 'class',
                    path: 'class', // 不要写成/class
                    component: ClassInfo
                },
                {
                    name: 'teacher',
                    // params传参
                    path: 'teacher',// 不要写成/teacher
                    component: TeacherInfo,
                    // props第三种写法,值为函数,return返回一个对象的每一组key-value以props的形式传给teacher组件。
                    props(route){
                        return{
                            id: route.query.id,
                            name: route.query.name
                        }
                    }
                }
            ]
        }
    ]

})

也可使用解构赋值的写法:

props({query}){
    return{
        id: query.id,
        name: query.name
    }
}

teacher组件

<template>
    <div>
        这是学校里面老师的信息+{{this.id}}+{{this.name}}
    </div>
</template>

<script>
export default {
    name: 'TeacherInfo',
    props:['id','name']
}
</script>

<style  lang="less">

</style>

image.png

router-link的replace属性

浏览器历史记录的写入方式,push是追加历史记录,replace是替换当前记录。

router-link路由跳转时默认的是push模式(可前进后退)。

image.png

开启replace模式:

班级信息

编程式路由导航

编程式路由导航是一种全新的路由方式。

不用router-link实现路由的跳转,让路由跳转更加灵活。

push方式:

this.$router.push({
    name:'student',
    query: {
        id: 888,
        name: 888
    }
})

replace方式:

this.$router.replace({
    name:'student',
    query: {
        id: 888,
        name: 888
    }
})

params传参,当页面刷新时,参数丢失。可在路由文件相关路由下配置占位符,刷新页面后参数不丢失。

query传参,数据会出现在url上面。

若query里面是个对象,需要先使用JSON.stringify()转换成字符串,收参数的页面需要使用JSON.parse()将字符串转换成对象。

前进:this.$router.forward();

后退:this.$router.back();

前进或者后退指定步数(负数后退,正数前进):this.$router.go(6);

缓存路由组件

让不展示的路由组件保持挂载不被销毁。

缓存1个路由组件

 <keep-alive include="TeacherInfo">
        <router-view></router-view>
</keep-alive>

缓存多个路由组件

 <keep-alive :include="['TeacherInfo','StudentInfo']">
        <router-view></router-view>
</keep-alive>

不写include,表示在里面显示的组件全部缓存。

写include时,里面写组件名,表示只缓存该组件。exclude表示里面的不缓存。

同样,可以在路由文件index.js中配置:

// 该文件用于创建整个应用的路由器

// 引入Vue
import Vue from "vue";
// 引入路由插件
import VueRouter from "vue-router";
// 引入组件
import StudentList from '@/components/StudentList'
import SchoolList from '@/components/SchoolList'
import ClassInfo from '@/components/ClassInfo'
import TeacherInfo from '@/components/TeacherInfo'

//使用插件
Vue.use(VueRouter);

// 创建一个路由器并暴露出去
export default new VueRouter({
    // 设置路由模式
    mode:'history',
    //全部路由
    routes: [
        {
            name: 'student', //名字自定义,不受其他参数影响。
            path: '/student',
            component: StudentList,
            meta:{
                keepAlive:false
            },
        },
        {
            name: 'school',
            path: '/school',
            component: SchoolList,
            meta:{
                keepAlive:false
            },
            // 通过设置children配置子级路由
            children:[
                {
                    name: 'class',
                    path: 'class', // 不要写成/class
                    component: ClassInfo,
                    meta:{
                        keepAlive:false
                    },
                },
                {
                    name: 'teacher',
                    path: 'teacher',
                    component: TeacherInfo,
                    // 使用路由中的meta属性来控制路由缓存
                     meta:{
                        keepAlive:true
                    },
                }
            ]
        }
    ]

})

这里是把teacher路由的meta属性设置为keepAlive:true,表示当前组件要进行缓存,然后:

<keep-alive>
    <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>

里面包含需要缓存的组件

<keep-alive> 
    <!-- 动态组件 -->
    <component /> 
</keep-alive>

对于缓存路由组件,这篇文章讲得很好:juejin.cn/post/684490…

生命周期activated和deactivated

因为使用缓存组件后,该组件

路由组件所独有的两个钩子:activated和deactivated。

activated:路由组件被激活时触发。

deactivated:路由组件停用时触发。

keep-alive对组件进行了缓存所以并不会再一次执行创建和挂载。

简单的说activated()函数就是一个页面激活后的钩子函数,一进入页面就触发;

所以当我们运用了组件缓存时,如果想每次切换都发送一次请求的话,需要把请求函数写在activated中,而写在created或mounted中其只会在首次加载该组件的时候起作用。deactivated是离开组件时被触发,而写在beforeDestroy中的不会被触发。

在第一次进入页面时,钩子的触发顺序created-> mounted-> activated,退出时触发deactivated。当再次进入(前进或者后退)时,只触发activated。如下图所示:

image.png

缓存的路由组件实现文字透明度的变化

<template>
    <div>
        <span :style="{opacity}">
            这是学校里面老师的信息+{{this.id}}+{{this.name}}
        </span>
        
        <input type="text"/>
    </div>
</template>

<script>
export default {
    name: 'TeacherInfo',
    props:['id','name'],
    data(){
        return{
            opacity: 1
        }
    },
    activated(){
        console.log('activated');
        this.timer = setInterval(()=>{
            this.opacity -= 0.01;
            if(this.opacity <= 0) this.opacity = 1;
        },16)
    },
    deactivated(){
        console.log('deactivated');
        clearInterval(this.timer);
    }
}
</script>

<style  lang="less">

</style>

路由守卫

全局前置路由守卫

全局前置路由守卫是在初始化的时候被调用或路由切换前被调用。

在路由文件index.js中调用路由的beforeEach。

// 该文件用于创建整个应用的路由器

// 引入Vue
import Vue from "vue";
// 引入路由插件
import VueRouter from "vue-router";
// 引入组件
import StudentList from '@/components/StudentList'
import SchoolList from '@/components/SchoolList'
import ClassInfo from '@/components/ClassInfo'
import TeacherInfo from '@/components/TeacherInfo'

//使用插件
Vue.use(VueRouter);

// 创建一个路由器并暴露出去
const router = new VueRouter({
    // 设置路由模式
    mode:'history',
    //全部路由
    routes: [
        {
            name: 'student', //名字自定义,不受其他参数影响。
            path: '/student',
            component: StudentList
        },
        {
            name: 'school',
            path: '/school',
            component: SchoolList,
            // 通过设置children配置子级路由
            children:[
                {
                    name: 'class',
                    path: 'class', // 不要写成/class
                    component: ClassInfo
                },
                {
                    name: 'teacher',
                    // params传参
                    path: 'teacher',// 不要写成/teacher
                    component: TeacherInfo,
                    meta: {
                        keepAlive: true
                    },
                    // props第三种写法,值为函数。
                    props({query}){
                        return{
                            id: query.id,
                            name: query.name
                        }
                    }
                }
            ]
        }
    ]

})

// 全局前置路由
router.beforeEach((to,from,next)=>{
    console.log(to,from)
})

export default router

在beforeEach中有to,from,next。

比如从班级组件进入到老师组件,to和from打印出来的信息:

image.png

to为到达组件的信息,from是从哪个组件切换的信息。主要包括组件路径和组件名。

比如在本地储存中有一个职位信息,当从学生组件进入到老师组件时,判断职位是否为教师(isTeacher),其他组件切换不做要求,若不是则提示不能进入。

// 全局前置路由
router.beforeEach((to,from,next)=>{
    // 可以使用path也可以使用name,这里使用name。
    if( to.name == 'teacher' && from.name == 'student' && localStorage.getItem('degree') !== 'isTeacher'){
        alert('你不是老师,学生不能进入!');
    }else{
        // 放行
        next();
    }
})

比如在本地储存中有一个学校信息,当进入到班级组件或老师组件时,判断学校是否为university,其他组件切换不做要求,若不是则提示学校不是university。

// 全局前置路由
router.beforeEach((to,from,next)=>{
    // 可以使用path也可以使用name,这里使用name。
    if( to.name == 'teacher' || to.name == 'class' ){
        // 判断信息
        if(localStorage.getItem('schoolInfo') == 'university'){
            // 消息正确放行路由
            next();
        }else{
            // 消息不正确,拦截路由跳转。
            alert('学校不是university');
        }
    }else{
        // 放行
        next();
    }
})

当路由限制过多时,to.name == 'teacher' || to.name == 'class' || ...就太多了,这里可以给每个路由设置一个属性,当该属性值为某个值时,再做路由的限制。

在这里就要知道路由元信息meta,这里面就可以放一些自定义的信息。需要权限的路由就设置meta,不需要权限的路由就不需要meta,因为没有这个属性就是undefined,就为false。

通过meta来设置进入teacher和class路由权限:

路由文件index.js

// 该文件用于创建整个应用的路由器

// 引入Vue
import Vue from "vue";
// 引入路由插件
import VueRouter from "vue-router";
// 引入组件
import StudentList from '@/components/StudentList'
import SchoolList from '@/components/SchoolList'
import ClassInfo from '@/components/ClassInfo'
import TeacherInfo from '@/components/TeacherInfo'

//使用插件
Vue.use(VueRouter);

// 创建一个路由器并暴露出去
const router = new VueRouter({
    // 设置路由模式
    mode:'history',
    //全部路由
    routes: [
        {
            name: 'student', //名字自定义,不受其他参数影响。
            path: '/student',
            component: StudentList
        },
        {
            name: 'school',
            path: '/school',
            component: SchoolList,
            // 通过设置children配置子级路由
            children:[
                {
                    name: 'class',
                    path: 'class', // 不要写成/class
                    component: ClassInfo,
                    meta: {
                        isAuth: true,
                    },
                },
                {
                    name: 'teacher',
                    // params传参
                    path: 'teacher',// 不要写成/teacher
                    component: TeacherInfo,
                    meta: {
                        keepAlive: true,
                        isAuth: true,
                    },
                    // props第三种写法,值为函数。
                    props({query}){
                        return{
                            id: query.id,
                            name: query.name
                        }
                    }
                }
            ]
        }
    ]

})

// 全局前置路由
router.beforeEach((to,from,next)=>{
    // 使用meta的isAuth属性判断
    if( to.meta.isAuth){
        // 判断信息
        if(localStorage.getItem('schoolInfo') == 'university'){
            // 消息正确放行路由
            next();
        }else{
            // 消息不正确,拦截路由跳转。
            alert('学校不是university');
        }
    }else{
        // 放行
        next();
    }
})

export default router

其中,next参数的使用如下所示:

next() // 路由正常跳转。
next('/') // 回到首页。
next(false) // 在当前路由不跳转。
next(to.path) // 强制跳转至指定路由。

全局后置路由守卫

全局后置路由守卫是在初始化的时候被调用或路由切换后被调用。

比如切换成功后把标题改为切换后的那个组件对应的名字。先在meta中配置title属性,再在后置路由守卫中设置,当然前置路由守卫也可以设置,但是需要判断,没有后置守卫简单。

路由文件index.js

// 该文件用于创建整个应用的路由器

// 引入Vue
import Vue from "vue";
// 引入路由插件
import VueRouter from "vue-router";
// 引入组件
import StudentList from '@/components/StudentList'
import SchoolList from '@/components/SchoolList'
import ClassInfo from '@/components/ClassInfo'
import TeacherInfo from '@/components/TeacherInfo'

//使用插件
Vue.use(VueRouter);

// 创建一个路由器并暴露出去
const router = new VueRouter({
    // 设置路由模式
    mode:'history',
    //全部路由
    routes: [
        {
            name: 'student', //名字自定义,不受其他参数影响。
            path: '/student',
            component: StudentList,
            meta: {
                title: '学生'
            }
        },
        {
            name: 'school',
            path: '/school',
            component: SchoolList,
            meta: {
                title: '学校'
            },
            // 通过设置children配置子级路由
            children:[
                {
                    name: 'class',
                    path: 'class', // 不要写成/class
                    component: ClassInfo,
                    meta: {
                        isAuth: true,
                        title: '班级'
                    },
                },
                {
                    name: 'teacher',
                    // params传参
                    path: 'teacher',// 不要写成/teacher
                    component: TeacherInfo,
                    meta: {
                        keepAlive: true,
                        isAuth: true,
                        title: '老师'
                    },
                    // props第三种写法,值为函数。
                    props({query}){
                        return{
                            id: query.id,
                            name: query.name
                        }
                    }
                }
            ]
        }
    ]

})

// 全局前置路由
router.beforeEach((to,from,next)=>{
    // 使用meta的isAuth属性判断
    if( to.meta.isAuth){
        // 判断信息
        if(localStorage.getItem('schoolInfo') == 'university'){
            // 消息正确放行路由
            next();
        }else{
            // 消息不正确,拦截路由跳转。
            alert('学校不是university');
        }
    }else{
        // 放行
        next();
    }
})

// 全局后置路由
router.afterEach((to,from)=>{
    console.log(to,from);
    // 路由切换成功后设置当前标题,当meta.title不存在时,标题名为系统名字。
    document.title = to.meta.title || '系统名字';
})

export default router

独享路由守卫

独享路由守卫是某个路由独享的。如只设置进入老师组件时的路由权限设置,就在老师组件路由设置beforeEnter。里面代码实现逻辑和前置路由守卫是一样的。

路由文件index.js

// 该文件用于创建整个应用的路由器

// 引入Vue
import Vue from "vue";
// 引入路由插件
import VueRouter from "vue-router";
// 引入组件
import StudentList from '@/components/StudentList'
import SchoolList from '@/components/SchoolList'
import ClassInfo from '@/components/ClassInfo'
import TeacherInfo from '@/components/TeacherInfo'

//使用插件
Vue.use(VueRouter);

// 创建一个路由器并暴露出去
const router = new VueRouter({
    // 设置路由模式
    mode:'history',
    //全部路由
    routes: [
        {
            name: 'student', //名字自定义,不受其他参数影响。
            path: '/student',
            component: StudentList,
            meta: {
                title: '学生'
            }
        },
        {
            name: 'school',
            path: '/school',
            component: SchoolList,
            meta: {
                title: '学校'
            },
            // 通过设置children配置子级路由
            children:[
                {
                    name: 'class',
                    path: 'class', // 不要写成/class
                    component: ClassInfo,
                    meta: {
                        isAuth: true,
                        title: '班级'
                    },
                },
                {
                    name: 'teacher',
                    // params传参
                    path: 'teacher',// 不要写成/teacher
                    component: TeacherInfo,
                    meta: {
                        keepAlive: true,
                        isAuth: true,
                        title: '老师'
                    },
                    // props第三种写法,值为函数。
                    props({query}){
                        return{
                            id: query.id,
                            name: query.name
                        }
                    },
                    // 独享路由守卫
                    beforeEnter: ((to, from, next) => {
                        console.log(to,from);
                        if( to.meta.isAuth){
                            // 判断信息
                            if(localStorage.getItem('degree') == 'isTeacher'){
                                // 消息正确放行路由
                                next();
                            }else{
                                // 消息不正确,拦截路由跳转。
                                alert('你不是老师,学生不能进入!');
                            }
                        }else{
                            // 放行
                            next();
                        }
                    })
                }
            ]
        }
    ]

})

// // 全局前置路由
// router.beforeEach((to,from,next)=>{
//     // 使用meta的isAuth属性判断
//     if( to.meta.isAuth){
//         // 判断信息
//         if(localStorage.getItem('schoolInfo') == 'university'){
//             // 消息正确放行路由
//             next();
//         }else{
//             // 消息不正确,拦截路由跳转。
//             alert('学校不是university');
//         }
//     }else{
//         // 放行
//         next();
//     }
// })

// 全局后置路由
router.afterEach((to,from)=>{
    console.log(to,from);
    // 路由切换成功后设置当前标题,当meta.title不存在时,标题名为系统名字。
    document.title = to.meta.title || '系统名字';
})

export default router

组件内路由守卫

组件内路由守卫,beforeRouteEnter和beforeRouteLeave。

beforeRouteEnter:进入守卫,通过路由规则,进入该组件时被调用。

beforeRouteLeave:离开守卫,通过路由规则,离开该组件时被调用。

路由文件index.js:

// 该文件用于创建整个应用的路由器

// 引入Vue
import Vue from "vue";
// 引入路由插件
import VueRouter from "vue-router";
// 引入组件
import StudentList from '@/components/StudentList'
import SchoolList from '@/components/SchoolList'
import ClassInfo from '@/components/ClassInfo'
import TeacherInfo from '@/components/TeacherInfo'

//使用插件
Vue.use(VueRouter);

// 创建一个路由器并暴露出去
const router = new VueRouter({
    // 设置路由模式
    mode:'history',
    //全部路由
    routes: [
        {
            name: 'student', //名字自定义,不受其他参数影响。
            path: '/student',
            component: StudentList,
            meta: {
                title: '学生'
            }
        },
        {
            name: 'school',
            path: '/school',
            component: SchoolList,
            meta: {
                title: '学校'
            },
            // 通过设置children配置子级路由
            children:[
                {
                    name: 'class',
                    path: 'class', // 不要写成/class
                    component: ClassInfo,
                    meta: {
                        isAuth: true,
                        title: '班级'
                    },
                },
                {
                    name: 'teacher',
                    // params传参
                    path: 'teacher',// 不要写成/teacher
                    component: TeacherInfo,
                    meta: {
                        keepAlive: true,
                        isAuth: true,
                        title: '老师'
                    },
                    // props第三种写法,值为函数。
                    props({query}){
                        return{
                            id: query.id,
                            name: query.name
                        }
                    },
                }
            ]
        }
    ]

})
export default router

teacher组件

<template>
  <div>
    <span :style="{ opacity }">
      这是学校里面老师的信息+{{ this.id }}+{{ this.name }}
    </span>

    <input type="text" />
  </div>
</template>

<script>
export default {
    name: 'TeacherInfo',
    props:['id','name'],
    data(){
        return{
            opacity: 1
        }
    },
    activated(){
        console.log('activated');
        this.timer = setInterval(()=>{
            this.opacity -= 0.01;
            if(this.opacity <= 0) this.opacity = 1;
        },16)
    },
    deactivated(){
        console.log('deactivated');
        clearInterval(this.timer);
    },
    // 通过路由规则,进入该组件时被调用。
    beforeRouteEnter(to,from,next){
        console.log(to,from,next);
        //使用meta的isAuth属性判断
        if( to.meta.isAuth){
            // 判断信息
            if(localStorage.getItem('degree') == 'isTeacher'){
                // 消息正确放行路由
                next();
            }else{
                // 消息不正确,拦截路由跳转。
                alert('你不是老师,学生不能进入!');
            }
        }else{
            // 放行
            next();
        }
    },
    // 通过路由规则,离开该组件时被调用。
    beforeRouteLeave(to,from,next) {
            console.log(to,from,next);
            next();
    }
}
</script>

<style  lang="less">
</style>