• vue(路由router、路由传参、嵌套、路由守卫)


    什么是路由

    • 简单来说,路由就是一个路径指向一个组件,比如我们点击主页,就显示主页的组件,点击其他就显示其他的组件,也可以说是路径和组件的映射关系
    • 路由中有三个基本的概念
      1. route,指的是一条路由,如点击主页,显示主页的组件,这就是一条路由,我们在打印它时,能够获取到路由中的各项参数
      2. routes,这指的是一组路由,里面包含了多条路由,是一个数组,我们在配置路由时,就要将配置好的路由放在这个数组中
      3. router,是一种机制,用来管理设置路由的,我们配置路由,就要在router实例中进行。

    创建路由的步骤

    1. 引入路由的js文件
    2. 配置路由项(先声明,再在router中进行配置地址)
    3. 将路由规则挂载在vue实例中
    4. 控制组件的点击与显示
    <!-- 1. 先在head中引用router.js -->
        <div id="app">
            <!-- 4.设置元素的显示 -->
            <!-- to里面写的路径名与配置项中的路径名相同 -->
            <!-- 这里的每一项相当于一个按钮,默认解析为a标签,可以通过tag属性进行修改 -->
            <router-link to="/jay" tag="span">周杰伦</router-link>
            <router-link to="/lili" tag="span">李雷</router-link>
            <router-link to="/mike" tag="span">麦克</router-link>
            <!-- 相当于一个占位符,标签里面不写内容,与插槽中的slot标签类似,相当于一个显示器 -->
            <router-view></router-view>
        </div>
        <script>
                // 2.路由配置项
    		// 先创建几个组件
            let jay = {
                template: `<div>周杰伦</div>`
            }
            let lili = {
                template: `<div>李雷</div>`
            }
            let mike = {
                template: `<div>麦克</div>`
            }
    		// 配置路由的地址
            let router = new VueRouter({
                routes: [
                    {
                        path:"/jay",    // 路径名可以自己定义,一般和组件名相同
                        component:jay   // 填写组件名
                    },
                    {
                        path:"/lili",
                        component:lili
                    },
                    {
                        path:"/mike",
                        component:mike
                    }
                ],
                mode:"hash"   // 默认为hash  一般app使用hash   后台管理使用history
            })
            new Vue({
                el: '#app',
                router,   // 3.将路由挂载在实例上,完整是 router:router ,但由于键值相同,可以只把键写出来
                data() {
                    return {
    
                    }
                },
                methods: {
    
                }
            });
        </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    注意

    • 在配置路由项时,routes是一个数组,要把我们的组件以数组的形式进行整合
    • 而每一个组件又是以对象的形式进行编写的,其中有两项是我们必要的:path和component。
      1. path是我们设置的指向组件的地址,要以“/”开头,一般为了方便辨认,地址名可以写成与组件名相同
      2. component是指向的组件名,不需要引号,直接将组件名写在这里即可
    • 当我们想要进入页面时,就能看到一个默认的组件显示出来时,我们需要使用到redirect属性了。在routes中添加一项,其中要写上:
     {
    	path:"/",
    	redirect:"/组件名"   // 重定向路径
    }
    
    • 1
    • 2
    • 3
    • 4

    这样就可以在打开页面时,显示我们想要默认显示的组件了。

    • routes中的对象里还可以添加name属性,这个属性对于路由的传参中会有一定的帮助
    • 在配置路由中,我们还可以设置一个属性:mode,它默认为hash,还可以设置为history
      1. 设置为hash时,跳转组件后,会将组件的地址拼接在地址栏中#的后面,它不会包含在http请求中,对后端也没有影响,因此改变hash之后,页面时不会进行刷新的
      2. 设置为history后,跳转组件url会直接被组件的真实路径覆盖,这样路由就是地址的一部分,在刷新页面后就会重新进行请求

    一般我们在写app时用hash,在操作后台管理时用history比较多

    路由传参

    路由传参有两种方式,一种是query,一种是params

    1. query
      直接在router-link标签中的to属性上面进行进行拼接,/地址?id=1,要先写一个问号,然后在后面进行拼接,参数直接进入query中
    <router-link to="/lilei?id=3" tag="span">李雷</router-link>
    
    • 1

    我们想要获取拼接的内容时,在定义的组件中使用mounted钩子,就可以通过this.$route获取到此条路由上的参数,this.$route.query就能找到对应的query中的参数

     let lilei={
        template:`<div>李雷</div>`,
        mounted() {
            console.log(this.$router);  // 打印整个路由
            console.log(this.$route);   // 打印路由的参数
            console.log(this.$route.query);   // {id: '3'}
        },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. params
      在配置路由规则中,在path后面通过/:参数名1/:参数名2的形式,将我们需要的参数进行设置,这里相当于函数中的一个形参,接着再router-link标签的to属性中进行拼接,/地址/参数1/参数2,这样就将参数传好了。
      				<router-link to="/hanmeimei/3/10" tag="span">韩梅梅</router-link>
      				-----------------------------------------------------------------------------
      				{
                        // 传参方式二 在path中设置要拼接什么参数,然后在router-link标签的to后面按顺序拼接
                        path:"/hanmeimei/:id/:key",
                        component:hanmeimei ,
                        name:"hanmeimei"
                    },
                            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    我们想要获取拼接的内容时,在定义的组件中使用mounted钩子,就可以通过this.$route获取到此条路由上的参数,this.$route.params就能找到对应的params中的参数

        let hanmeimei = {
        template:`<div>韩梅梅</div>`,
        mounted() {
            console.log(this.$router);
            console.log(this.$route);
            console.log(this.$route.params);   // {id: '3', key: '10'}
        },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    事件触发路由

    除了使用router-link标签设置路由的点击项,我们还可以通过事件,对路由进行调用,而这个中也存在了传参的问题
    我们先来看看如何使用事件触发路由,我们可以使用点击、按键按下、鼠标经过等事件,接下来举例会用到点击事件

    1. 首先创建一个按钮,绑定一个点击事件
    <!-- 事件触发 -->
            <button @click="cli('mike')">点击麦克</button>
    
    • 1
    • 2
    1. 设置点击事件,给router中push一条路由,在这个期间,我们就可以将参数写在query或者params中了
            cli(e){
                this.$router.push({
    
                    name:e,
                    query:{
                        id:10,
                        key:20
                    },
                    params:{
                        name:99  // 刷新了就没有了
                    }
                })
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    我们可以看到,这这里我就用到了之前提的name,但其实这里的name也不是必须的,如果我们只使用query传参,就可以不用写name,而是直接写path,将需要跳转的组件的地址写过来即可,这样就不必在配置路由规则时,给路由添加name属性了。但是我们在这里写了name之后,也就不用写path了,同样也能进行跳转,(注意:这里的name要和跳转的组件的name是相同的),我们要是想用params进行传参就一定要有name这个属性。但是params中的参数就类似是一次性的,在刷新以后就没有了。

    路由嵌套

    路由嵌套呈现的效果就相当于,点击主页跳转到主页的组件,主页的组件中又包含了路由,点击主页组件中的元素,能够显示其他的组件

    1. 首先我们就要将这些嵌套的组件进行一个声明
    2. 然后就要对它们进行配置路由规则:在它们的父级路由配置里面添加一个children,children是一个数组,这些嵌套的组件就在children里面正常地进行配置即可

    注意项:在配置嵌套组件设置path时,路径名前面不用加上“/”,在router-link标签的to属性中,要将父级的地址写在子级的前面/父级地址/子级地址。整个点击组件以及显示组件,都要放在父级的template中

     <div id="app">
            <router-link to="/mike">麦克</router-link>
            <router-link to="/jack">杰克</router-link>
            <router-link to="/ironMan">钢铁侠</router-link>
            <router-view></router-view>
        </div>
        <script>
            let mike = {
                template: `<div>麦克</div>`
            }
            let jack = {
                template: `<div>杰克</div>`
            }
            let spiderMan = {
                template: `<div>蜘蛛侠</div>`
            }
            let arrowMan = {
                template: `<div>绿箭侠</div>`
            }
            let beeMan = {
                template: `<div>青蜂侠</div>`
            }
            let ironMan = {
                // 嵌套的路由的地址前面,要加上父级组件的地址
                template: `<div class="box"> <div>钢铁侠</div>
                    <router-link to="/ironMan/spiderMan">蜘蛛侠</router-link>
                    <router-link to="/ironMan/arrowMan">绿箭侠</router-link>
                    <router-link to="/ironMan/beeMan">青蜂侠</router-link>
                    <router-view></router-view>
                    </div>`
            }
            const router = new VueRouter({
                routes: [
                    {
                        path: "/mike",
                        component: mike
                    },
                    {
                        path: "/jack",
                        component: jack
                    },
                    {
                        path: "/ironMan",
                        component: ironMan,
                        // 嵌套
                        children: [
                            {
                                path: "spiderMan",
                                component: spiderMan
                            },
                            {
                                path: "arrowMan",
                                component: arrowMan
                            },
                            {
                                path: "beeMan",
                                component: beeMan
                            },
                        ]
                    }
                ]
            })
            new Vue({
                el: '#app',
                data() {
                    return {
                    }
                },
                methods: {
                },
                router,
            });
        </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    路由守卫

    使用路由的钩子函数,检测整个路由跳转的过程,可以在进入组件前或者进入组件后进行一些操作
    路由守卫也有一定的分类:全局守卫、组件守卫、路由独享守卫。我们来看看它们都有哪些钩子函数


    全局守卫
    在全局进行使用
    beforeEach 进入组件之前
    afterEach 进入组件之后

            router.beforeEach((to, from, next) => {
                console.log(to,"全局to");   // 跳转到哪一个组件
                console.log(from,"全局from");  // 从哪个组件跳转的
                next()   // next是一个回调函数,()里可以放地址,前往哪一个组件
            })
    
    • 1
    • 2
    • 3
    • 4
    • 5

    需要注意的是,全局守卫要放在路由配置规则的后面,否则由于路由规则还未配置好,可能会报错


    组件守卫
    在各个组件中使用
    beforeRouteEnter 进入组件前
    afterRouteEnter 进入组件后

            let mike = {
                template: `<div>麦克</div>`,
                beforeRouteEnter(to, from, next) {
                    console.log(to, "组件守卫的to");
                    next()
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    路由独享
    在路由配置中使用
    beforeEnter 进入组件前
    afterEnter 进入组件后

            let router = new VueRouter({
                routes: [
    
                    {
                        path:"/lili",
                        component:lili,
                        // 路由独享
                        beforeEnter: (to, from, next) => {
                            console.log(to,"路由独享的to");
                            next();
                        }
                    },
    
                ],
    
            })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    路由守卫钩子的总结

    我们可以看到,这些钩子都可以看到,页面跳转的一个过程:从哪个组件跳转(from),要跳转到哪一个组件(to)。其实这三类路由守卫,除了书写的地方不同,其他的作用以及参数都是相同的,而进入组件后的钩子用法是与进入组件前的钩子用法是相同的,而且相对来说进入组件后的钩子用的是很少的,所以就没有进行举例了,如果感兴趣可以自己试一试。


    不过这几个钩子中有一个参数是要着重强调的:next,它是一个回调函数,()里填的是地址,表示前往哪一个组件,如果不填那么久跳转到默这条路由中默认的组件。这个回调函数很重要,如果使用了这些钩子,而不调用这个回调函数的话,那么组件是不会进行跳转的


    对于路由守卫,我们有一个用法是用它来进行控制访问权限,这里有一段代码,它是用于模拟判断用户是否登录,如果登录就进行下一步操作,没有登录就跳转到登录组件

    router.beforeEach((to, from, next) => {
                if(sessionStorage.getItem("user")){   // 判断缓存中是否有用户信息
                    next()   // 执行下一步,如果没有next()就不会执行下一步了,很重要
                }else{    // 以下是没有登录的情况
                    if(to.path==="/login"){
                        next()    // 如果要去的组件是登录组件,就执行
                    }else{
                        next("/login")    // 如果要去的组件不是登录组件,就强制去登录组件
                    }
                }
            })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    另外我们还可以了解一下,从一个组件到另一个组件,我们要经历的钩子的顺序

    1. 先从前一个组件出来,beforeRouteLeave
    2. 到全局下,beforeEach
    3. 根据路由跳转,beforeEnter
    4. 进入下个组件,beforeRouterEnter
    5. 所有的时间全部结束,afterEach

    监听路由

    除了使用以上的钩子来获取到从哪个组件跳转到哪个组件,我们还可以通过监听器来获取

                watch: {   // 通过监听,监听路由
                    "$route"(e, o) {
                        console.log(e.path);   // 当前组件的地址
                        console.log(o.path);   // 上一个组件的地址
                    }
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    总结

    今天讲的路由是很重要的,涉及到了怎么配置路由规则、怎么传参、怎么进行路由的嵌套以及路由守卫,我们了解到了很多的理论知识,但是如果缺乏实践、案例的支持,我们对路由的了解是很少的,希望在接下来的项目中,不断夯实自己对于路由的理解,到时一定会再来对这篇文章进行修改的。
    接下来,针对于今天所学,我进行了一个总体的运用:从配置路由到传参、嵌套、守卫进行一个融合,放在一个案例中。上面的理论融合了很多自己的理解,可能会不太对,但是案例是没毛病的,如果有的话那就得改了

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>路由总体</title>
        <script src="./js/vue.min.js"></script>
        <script src="./js/vue-router.js"></script>
        <!-- 1.先引入路由的js文件 -->
        <style>
            .tip {
                display: inline-block;
                width: 200px;
                line-height: 30px;
                text-align: center;
                cursor: pointer;
            }
    
            .box {
                background-color: #0ff;
                color: rgb(250, 243, 243);
                padding: 50px;
                width: fit-content;
            }
        </style>
    </head>
    
    <body>
        <div id="app">
            <!-- 4. 控制显示 -->
            <router-link to="/cat/20/30" tag="span" class="tip">小猫</router-link>
            <router-link to="/dog" tag="span" class="tip">小狗</router-link>
            <!-- 第一种传参方式,query 直接在router-link标签的to属性中拼接  ?参数名=参数 -->
            <router-link to="/tiger?id=20" tag="span" class="tip">老虎</router-link>
            <router-link to="/morea" tag="span" class="tip">更多</router-link>
            <router-view></router-view>
    
            <!-- 事件控制路由 -->
            <!-- 暂时只能点击一次,点多了会报错 -->
            <button @click="dogShow">点击到小狗</button>
    
    
        </div>
        <script>
            // 2.配置路由
            let cat = {
                template: `<div class="box">小猫</div>`,
                mounted() {
                    console.log(this.$route, "小猫");
                },
                beforeRouteEnter(to, from, next) {
                    console.log(to, "这是组件守卫中的to");   // 跳转到哪一个组件
                    console.log(from, "这是组件守卫中的from");    // 从哪一个组件跳转来
                    next()   // 执行下一步
                }
            }
            let dog = {
                template: `<div class="box">小狗</div>`,
                mounted() {
                    console.log(this.$route, "小狗");
                },
                beforeRouteEnter(to, from, next) {
                    console.log(to, "这是组件守卫中的to");   // 跳转到哪一个组件
                    console.log(from, "这是组件守卫中的from");    // 从哪一个组件跳转来
                    next()   // 执行下一步
                }
            }
            let tiger = {
                template: `<div class="box">老虎</div>`,
                beforeRouteEnter(to, from, next) {
                    console.log(to, "这是组件守卫中的to");   // 跳转到哪一个组件
                    console.log(from, "这是组件守卫中的from");    // 从哪一个组件跳转来
                    next()   // 执行下一步
                }
            }
            let morea = {
                template: `<div class="box"><div>更多</div>
                <router-link to="/morea/bird" tag="span">小鸟</router-link>
            <router-link to="/morea/snake"  tag="span">大蟒蛇</router-link>
            <router-link to="/morea/chicken"  tag="span">大公鸡</router-link>
            <router-view></router-view>
                    </div>`
            }
            let bird = {
                template: `<div>小鸟</div>`
            }
            let snake = {
                template: `<div>大蟒蛇</div>`
            }
            let chicken = {
                template: `<div>大公鸡</div>`
            }
            const router = new VueRouter({
                routes: [
                    {
                        path: "/",
                        redirect: "/morea"    // 默认显示更多
                    },
                    {
                        // 第二种传参方式,在路由配置中的path中进行拼接,将参数名拼接在这里,将参数值拼接在router-link标签的to属性中
                        path: "/cat/:key/:id",
                        component: cat,
                        name: 'cat',
                        beforeEnter: (to, from, next) => {
                            console.log(to,"这是路由独享中的to")
                            console.log(from,"这是路由独享中的from");
                            next()   // 执行下一步
                        }
                    },
                    {
                        path: "/dog",
                        component: dog,
                        name: "dog",
                        beforeEnter: (to, from, next) => {
                            console.log(to,"这是路由独享中的to")
                            console.log(from,"这是路由独享中的from");
                            next()   // 执行下一步
                        }
                    },
                    {
                        path: "/tiger",
                        component: tiger,
                        name: "tiger",
                        beforeEnter: (to, from, next) => {
                            console.log(to,"这是路由独享中的to")
                            console.log(from,"这是路由独享中的from");
                            next()   // 执行下一步
                        }
                    },
                    {
                        path: "/morea",
                        component: morea,
                        name: "morea",
                        // 路由嵌套
                        children: [
                            {
                                path: "/morea",
                                redirect: "bird"    // 设置默认显示
                            },
                            {
                                path: "bird",
                                component: bird
                            },
                            {
                                path: "snake",
                                component: snake
                            },
                            {
                                path: "chicken",
                                component: chicken
                            }
                        ]
                    }
                ]
            })
            // 全局路由守卫
            router.beforeEach((to, from, next) => {
                console.log(to, "这是全局守卫的to");   // 到哪个组件
                console.log(from, "这是全局守卫的from");   // 从哪个组件来
                next()   // 执行下一步
            })
            new Vue({
                el: '#app',
                data() {
                    return {
    
                    }
                },
                methods: {
                    dogShow() {
                        this.$router.push({
                            name: "dog",
                            query: {    // 通过query传递参数,在url中拼接
                                id: 15
                            },
                            params: {
                                key: 50    // 相当于一个临时储存,刷新以后就会清空
                            }
                        })
                    }
                },
                // 3.挂载路由
                router,
                watch: {   // 通过监听,监听路由
                    "$route"(e, o) {
                        console.log(e.path);   // 当前组件的地址
                        console.log(o.path);   // 上一个组件的地址
                    }
                }
            });
        </script>
    </body>
    
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
  • 相关阅读:
    [游戏开发][Unity]安卓出包报错记录
    论文超详细精读|五千字:STGR
    23届前端面试选择题(长期更新)
    配电网稳定性的分析(Python代码实现)
    Vue+Vite+TS
    【VMware ESXi】HP Z4G4 Workstation安装ESXi停留在Shutting down firmware services...的解决办法。
    工作笔记-滚动列表中指定项到可是区域范围内
    AJAX基于XML的数据交换、XML和JSON的区别
    数字集成电路设计(五、仿真验证与 Testbench 编写)(四)
    Java#26(常见算法: 排序算法)
  • 原文地址:https://blog.csdn.net/m0_66970189/article/details/125529714