Vue-Router路由

118 阅读5分钟

vue-router是Vue的一个插件库,专门用来做SPA应用(single page web application)。

SPA(single page web application)应用就是单页Web应用,不会刷新页面,只做页面的局部更新。数据需要通过ajax请求获取。

路由

一个路由就是一组映射关系(key-value),key是路径,value是function或component。

路由分为前端路由和后端路由后端路由中的value是function。前端路由的value是component,用于页面内容,当浏览器的路径改变时,对应的组件就会显示。

比如下图就是前端路由根据不同路径展示不同的组件。

微信图片_20230816204915.jpg

路由的基本使用

安装vue-router插件

npm i vue-router

使用插件

Vue.use(VueRouter)

新建一个router/index.js文件编写router配置项

// 该文件专门创建整个应用的路由器
import VueRouter from "vue-router";
// 引入路由组件
import AboutPage from '../pages/AboutPage.vue';
import HomePage from '../pages/HomePage.vue';

// 创建并暴露一个路由器
export default new VueRouter({
    routes: [
        // 设置路由规则
        {
            path: '/about',
            component: AboutPage
        },
        {
            path: '/home',
            component: HomePage
        },
    ]
})

在组件中使用router-link标签实现切换(active-class可配置高亮样式),本质上就是a标签。

  • to属性 用于设置路径。
<router-link class="bla bltop" active-class="active" to="/about">About</router-link>
  • replace属性 用于设置页面跳转时操作浏览器记录的模式,push模式(默认)是追加历史记录,replace模式是替换当前记录。
<router-link replace to="/about" class="nav-top" active-class="active">
    <span>
        About
    </span>
</router-link>

在组件中使用router-view标签指定展示的位置

<router-view></router-view>

几个注意点:

  • 路由组件通常存放在pages文件夹中,一般组件通常存放在components文件夹中。
  • 通过切换,“隐藏”了的路由组件默认是被销毁的,需要的时候再去挂载。
  • 每个组件都有自己的route属性,其中存储着自己的路由信息,通过$route属性获取。
  • 整个应用只有一个router路由器,可以通过组的$router属性获得。

嵌套路由

嵌套路由在配置时需要在对应的父级路由规则中添加children配置项

routes: [
        {
            name: 'guanyu',
            path: '/about',
            components: {
                default: () => import('../pages/myAbout.vue'),
            }
        },
        {
            path: '/home',
            components: {
                default: () => import('../pages/myHome.vue'),
                myHomeList: () => import('../pages/myHomeList.vue')
            },
            children: [
                {
                    path: 'news',
                    components: {
                        default: () => import('../pages/myNews.vue')
                    }
                },
                {
                    path: 'message',
                    components: {
                        default: () => import('../pages/myMessage.vue')
                    },
                    children: [
                        {   path: 'detail',
                            component:() => import('../pages/myDetail.vue')
                        }
                    ]
                }
            ]
        },
    ],

组件中实现路由跳转时注意路径要写完整

            <router-link to="/home/message" active-class="active">
                <span>Message</span>
            </router-link>

命名路由

路由传参

第一种方式是组件可以通过query在页面跳转时传递参数,在to属性中使用问号?携带参数。

  • 传递展示列表的id和title属性。
<template>
    <div>
        <ul class="list">
            <li class="item" v-for="m in messageList" :key="m.id">
                <!-- to的字符串写法 -->
                <!-- <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{ m.title }}</router-link> -->
                <!-- to的对象写法 -->
                <router-link :to="{
                    path: '/home/message/detail',
                    query: {
                        id: m.id,
                        title: m.title
                    }
                }">{{ m.title }}</router-link>
            </li>
        </ul>
        <router-view></router-view>
    </div>
</template>

<script>
    export default {
        name: 'myMessage',
        data(){
            return {
                messageList: [
                    {id: '001', title: '消息001'},
                    {id: '002', title: '消息002'},
                    {id: '003', title: '消息003'},
                ]
            }
        }
    }
</script>
  • 组件通过query接收传递的id和title。
<ul>
    <li>消息编号:{{$route.query.id}}</li>
    <li>消息标题:{{$route.query.title}}</li>
</ul>

第二种方式是组件还可以通过params在页面跳转时传递参数,在to属性中使用斜线/携带参数。

  • 配置路由时要声明接收params参数。
{
    path: 'message',
    components: {
        default: () => import('../pages/myMessage.vue')
    },
    children: [
        {   path: 'detail/:id/:title', // 使用占位符声明接收params参数
            component:() => import('../pages/myDetail.vue')
        }
    ]
}
  • 组件传递参数时和query类似的,但要注意如果使用to的对象写法,则必须使用name配置,不能使用path。
<template>
    <div>
        <ul class="list">
            <li class="item" v-for="m in messageList" :key="m.id">
                <!-- to的字符串写法 -->
                <router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{ m.title }}</router-link>
                <!-- to的对象写法 -->
                <!-- <router-link :to="{
                    name: 'detail'
                    query: {
                        id: m.id,
                        title: m.title
                    }
                }">{{ m.title }}</router-link> -->
            </li>
        </ul>
        <router-view></router-view>
    </div>
</template>
  • 组件接收参数
<template>
    <ul>
        <li>消息编号:{{$route.params.id}}</li>
        <li>消息标题:{{$route.params.title}}</li>
    </ul>
</template>

除此之外,配置路由时可以通过props配置项让路由组件更方便收到参数,组件可以通过props配置项接收到参数,再应用到模板中。

children: [
    {   path: 'detail/:id/:title',
        component:() => import('../pages/myDetail.vue'),
        // props的第一种写法,该对象中的所有键值对都会通过props传给detail组件
        // props: {
        //     a: 1,
        //     b: 'hello'
        // }
        // 第二种写法,布尔值,布尔值为true,则把路由收到的params参数通过props传给detail组件
        // props: true,
        // 第三种写法:props为函数,该函数返回的对象中每一组键值对都会通过props传给detail组件,参数是$route 
        props($route){
            return {
                id: $route.params.id,
                title: $route.params.title
            }
        }
    }
]

编程式路由导航

不借助router-link标签实现路由跳转,让路由跳转更加灵活。

为此我们可以用router中两个个API实现任意标签路由跳转,并且可以设置他们的浏览器记录模式。

methods: {
    pushShow(m){
        // push模式
        this.$router.push({
            name: 'xiangqing',
            params: {
                id: m.id,
                title: m.title
            }
        })
    },
    repalceShow(m){
        // repalce模式
        this.$router.repalce({
            name: 'xiangqing',
            params: {
                id: m.id,
                title: m.title
            }
        })
    }
}

除了以上两种还有其它几种API

this.$router.forwrad() // 前进
this.$router.back() // 后退
this.$router.go() // 可前进可后退

缓存路由组件

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

<keep-alive include="News">
    <router-view>

    </router-view>
</keep-alive>

两个新的生命周期钩子

路由组件独有的两个钩子,用于捕获路由组件的激活状态。

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

deactivated() 路由组件失活时触发。

<script>
    export default {
        name: 'myNews',
        data(){
            return {
                messageList: [
                    {id: '001', title: '新闻001'},
                    {id: '002', title: '新闻002'},
                    {id: '003', title: '新闻003'},
                ]
            }
        },
        activated(){
            console.log('News组件激活了');
        },
        deactivated(){
            console.log('News组件停用了');
        }
    }
</script>

路由守卫

路由守卫是为了对路由进行权限控制,分为全局守卫、独享守卫,组件内守卫。

全局路由守卫

全局路由守卫又分为前置守卫和后置守卫。

全局前置路由守卫 初始化的时候被调用,每次路由切换之前也会被调用。

全局后置路由守卫 初始化的时候被调用,每次路由切换之后也会被调用。

meta属性 是路由配置项的一个对象属性,用户可以在其中自定义需要的属性。

// 全局前置路由守卫 初始化的时候被调用,每次路由切换之前也会被调用
router.beforeEach((to, from, next)=>{
    console.log('前置路由守卫', to, from);
    if(to.meta.isAuth){ // 判断是否需要鉴权
        if(localStorage.getItem('user') === 'kng'){
            next();
        }else{
            alert('用户权限不够');
        }
    }else{
        next();
    }
})

// 全局后置路由守卫 初始化的时候被调用,每次路由切换之后也会被调用
router.afterEach((to,from, next)=>{
    console.log('后置路由守卫', to, from, next);
    if(to.meta.title){
        document.title = to.meta.title; // 修改网页的title
    }else{
        document.title = 'vue_test';
    }
})

独享路由守卫

某一个路由独享的路由守卫,

beforeEnter: (to, from, next) => {
    console.log('独享路由守卫', to, from);
    if(to.meta.isAuth){ // 判断是否需要鉴权
        if(localStorage.getItem('user') === 'kng'){
            next();
        }else{
            alert('用户权限不够');
        }
    }else{
        next();
    }
}

组件内路由守卫

通过路由规则,进入或离开组件时被调用。

// 通过路由规则进入该组件时被调用
beforeRouteEnter (to, from, next) {
    console.log('App---beforeRouteEnter', to, from);
    if(to.meta.isAuth){ // 判断是否需要鉴权
        if(localStorage.getItem('user') === 'king'){
            next();
        }else{
            alert('用户权限不够');
        }
    }else{
        next();
    }
},
// 通过路由规则离开该组件时被调用
beforeRouteLeave (to, from, next) {
    console.log('App---beforeRouteLeave', to, from, next);
    next();
}

路由器的工作模式

路由器的工作模式有两种,history模式和hash模式。

对于一个url来说,hash值就是#号及其后面的内容,不会包含在HTTP请求中,即不会带给服务器。它虽然不美观但是兼容性比较好。

history模式的url地址干净美观,兼容性略差,部署上线时需要后端人员支持解决刷新页面服务端404的问题。