【Vue 学习】路由

一、介绍

route【路由】

  • 是一组 key-value 的映射关系
  • 前端路由和后端路由
    • 前端路由的作用:根据路径,局部刷新页面的内容
    • 后端路由的作用:根据请求路径,找到匹配的方法进行对应的处理并给出响应

router【路由器】

  • 管理多组路由规则

vue-router

  • vue 的一个插件库,专门用来实现 SPA 应用,实时监控路由的变化

对 SPA 应用的理解

  • 单页 Web 应用(single page web application,SPA)
  • 整个应用只有一个完整的页面
  • 点击页面中的导航链接不会刷新页面,只会做页面的局部更新
  • 数据需要通过 ajax 请求获取

二、路由的简单使用

1. 简单使用

安装 vue-router 插件

npm i vue-router@3

编写路由配置文件:src/router/index.js

import Vue from 'vue';
import VueRouter from "vue-router";
import MyAbout from "@/components/MyAbout.vue";
import MyHome from "@/components/MyHome.vue";

// 注册 vue-router 插件
Vue.use(VueRouter)

// 编写并暴露管理路由的规则,自定义的路由器
export default new VueRouter({
    
    
    routes: [
        {
    
    
            path: '/about',
            component: MyAbout,
        },{
    
    
            path: '/home',
            component: MyHome,
        }
    ],
})

引入自定义的路由器

import Vue from 'vue';
import App from './App.vue';

// 引入
import router from './router/index'

new Vue({
    
    
  el: '#app',
  // 注册
  router,
  render: h => h(App)
});

在模板中书写切换路由的代码

<template>
  <div>
    <router-link to="/about">About</router-link>
    <hr>
    <router-link to="/home">Home</router-link>
    <hr>
    <router-view></router-view>
  </div>
</template>

2. 注意事项

第一个注意点

组件分类

  • 一般组件:自己使用路由标签,一般书写在 src/components 里面
  • 路由组件:在路由器里面引入,然后在 router-link 使用,一般书写在 src/pages 里面

第二个注意点

组件如果被切换掉,被路由切换掉,那么被切换的组件会被销毁,可以使用生命周期验证,先销毁旧的,再切换挂载新的组件

第三个注意点

所有的 vm、vc 身上都增加了两个属性:$router$route

  • $route:每个组件有一个独立的 route
  • $router:整个项目只有一个 router,路由器只有一个

3. 嵌套路由

嵌套路由、多级路由

  • 一般情况下,最多只用到四五级路由

  • 二级路由以及之后的路由的 path 属性不要以 / 开头

export default new VueRouter({
    
    
    routes: [
        {
    
    
            path: '/about',
            component: MyAbout,
        },{
    
    
            path: '/home',
            component: MyHome,
            children: [
                {
    
    
                    path: 'a',
                    component: MyA,
                },{
    
    
                    path: 'b',
                    component: MyB,
                }
            ]
        }
    ],
})

4. 命名路由

配置路由:尽管通过 name 属性进行路由切换,path 属性依然不可省略

export default new VueRouter({
    
    
    routes: [
        {
    
    
            name: 'guanyu',
            path: '/about',
            component: MyAbout,
        },{
    
    
            name: 'zhuye',
            path: '/home',
            component: MyHome,
        }
    ],
})

直接使用 name 进行路由跳转

<template>
  <div>
    <router-link :to="{name:'guanyu'}">About</router-link>
    <hr>
    <router-link :to="{name:'zhuye'}">Home</router-link>
    <hr>
    <router-view></router-view>
  </div>
</template>

三、路由传参

1. query 传参

(1)传递参数

字符串写法:path

<router-link :to="`/about?id=${'002'}&name=${'tom'}&age=${178}`">About</router-link>

对象写法:path、name

<router-link :to="{
  path:'/about',
  query: {
    id: '001',
    name: 'tom',
    age: 19,
  }
}">About</router-link>
<router-link :to="{
  name:'guanyu',
  query: {
    id: '001',
    name: 'tom',
    age: 19,
  }
}">About</router-link>

(2)接收参数

<ul>
  <li>{
   
   { $route.query.id }}</li>
  <li>{
   
   { $route.query.name }}</li>
  <li>{
   
   { $route.query.age }}</li>
</ul>

2. params 传参

(1)先占位置

export default new VueRouter({
    
    
    routes: [
        {
    
    
            name: 'guanyu',
            // 使用 :XXX 来占位置
            path: '/about/:id/:name/:age',
            component: MyAbout,
        },{
    
    
            name: 'zhuye',
            path: '/home',
            component: MyHome,
        }
    ],
})

(2)传递参数

字符串传参:必须使用 path 来填充占位符

<router-link to="/about/006/jack/28">About</router-link>

对象传参:必须使用 name,因为 path 已经不可以精准匹配了

<router-link class="nav-title" :to="{
  name: 'guanyu',
  params: {
    id: 'abc',
    name: 'mary',
    age: 56
  }
}">About</router-link>

(3)接收参数

<ul>
  <li>{
   
   { $route.params.id }}</li>
  <li>{
   
   { $route.params.name }}</li>
  <li>{
   
   { $route.params.age }}</li>
</ul>

3. 通过路由的 props 参数传参

让路由组件更方便的接收数据

(1)写法一

配置 porps 属性,将所有的 k-v 数据传递到对应组件的 props 属性中

传递

export default new VueRouter({
    
    
    routes: [
        {
    
    
            name: 'guanyu',
            path: '/about',
            component: MyAbout,
            // 配置 porps 属性,将该属性所有的 k-v 数据传递到对应组件的 props 属性中
            props: {
    
    
                id: '001',
                name: 'jack001',
                age: 89
            }
        }
    ],
})

接收

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

使用

<ul>
  <li>{
   
   { id }}</li>
  <li>{
   
   { name }}</li>
  <li>{
   
   { age }}</li>
</ul>

(2)写法二

配置 porps 属性,将路由收到的所有 params 属性传递到对应组件的 props 属性中【不需要占位符】

传递

<router-link class="nav-title" :to="{
  name: 'guanyu',
  params: {
    id: 'ab5656c',
    name: 'mary',
    age: 56
  }
}">About
</router-link>

开启 props 转换

export default new VueRouter({
    
    
    routes: [
        {
    
    
            name: 'guanyu',
            path: '/about',
            component: MyAbout,
            // 转换
            props: true
        }
    ],
})

接收

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

使用

<ul>
  <li>{
   
   { id }}</li>
  <li>{
   
   { name }}</li>
  <li>{
   
   { age }}</li>
</ul>

(3)写法三

手动将 $router 的数据读取出来传递给对应组件的 props 属性上

传递

<router-link class="nav-title" :to="{
  name: 'guanyu',
  params: {
    id: 'abc',
    name: 'mary',
    age: 56
  }
}">About</router-link>

路由处理

export default new VueRouter({
    
    
    routes: [
        {
    
    
            name: 'guanyu',
            path: '/about',
            component: MyAbout,
            props($route) {
    
    
                return {
    
    
                    id: $route.params.id,
                    name: $route.params.name,
                    age: $route.params.age,
                }
            }
        }
    ],
})

也可以解构赋值

export default new VueRouter({
    
    
    routes: [
        {
    
    
            name: 'guanyu',
            path: '/about',
            component: MyAbout,
            props({
     
     params}) {
    
    
                return {
    
    
                    id: params.id,
                    name: params.name,
                    age: params.age,
                }
            }
        }
    ],
})

四、route-link 的历史记录模式

有两种工作模式

  • 【push】压栈模式:可以前进后退页面,route-link 的默认就是压栈模式
  • 【replace】替换模式:会干掉当前的记录,不可以前进后退页面

1. 压栈模式

<router-link to="/about">About</router-link>
<!-- OR -->
<router-link push to="/about">About</router-link>

2. 替换模式

<router-link replace to="/about">About</router-link>

五、编程式路由导航

  • <router-link> 最终会编译成 <a> 标签,所以可以在 <router-link> 标签上面写类名
  • 编程式路由使用 router 实现路由跳转,可以不使用 <router-link> 实现路由跳转,更灵活

1. 简单使用

<button class="nav-title" @click="toAbout">About</button>
<button class="nav-title" @click="toHome">Home</button>
<script>
export default {
  name: 'App',
  methods: {
    toAbout() {
      this.$router.push({
        name: 'guanyu',
        params: {
          id: '0514df',
          name: 'dsgfsd ',
          age: 59
        }
      })

    },
    toHome() {
      this.$router.push({
        path: '/home'
      })
    },
  }
}
</script>

2. 补充

this.$router.push({
    
    
    name: 'guanyu',
    params: {
    
    
        id: '0514df',
        name: 'dsgfsd ',
        age: 59
    }
})


this.$router.replace({
    
    
    name: 'guanyu',
    params: {
    
    
        id: '0514df',
        name: 'dsgfsd ',
        age: 59
    }
})


this.$router.forward()	前进


this.$router.back()		后退


this.$router.go(n)		可前进也可后退,n为正数前进n,为负数后退
this.$router.go(0)		刷新页面

六、缓存路由组件

作用:让不展示的路由组件保持挂载,不被销毁,可以通过钩子函数来验证

使用场景

  • 默认情况下,路由跳转使得组件切换,且切换的组件的用户临时输入的数据会消失,路由缓存可以解决该问题

1. 缓存使用的所有组件

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

2. 缓存指定组件

组件名称、组件名称、组件名称

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

<!-- 注意 `v-bind:` -->
<keep-alive :include=['MyAbout', 'MyHome']>
	<router-view></router-view>
</keep-alive>

七、路由组件专属的钩子函数

activated 和 deactivated 是路由组件所独有的两个钩子,用于捕获路由组件的激活状态

* activated 路由组件被激活时触发
* deactivated *路由组件失活时触发

对于被缓存的路由组件,路由切换时不会销毁组件,也就不会执行 destoryed 钩子函数,那么如下的定时器是不会被销毁的

<script>
export default {
  name: 'MyAbout',
  props: ['id', 'name', 'age'],
  mounted() {
    console.log('组件被挂载了,绑定了定时器')
    this.timer = setInterval(() => {
      this.opacity -= 0.01
      if (this.opacity <= 0) this.opacity = 1
    }, 10)
  },
  destoryed() {
    console.log('组件销毁了,解绑了定时器')
    clearInterval(this.timer)
  }
}
</script>

使用 activated、deactivated 即可解决问题

<script>
export default {
  name: 'MyAbout',
  props: ['id', 'name', 'age'],
  activated() {
    console.log('组件被激活了,绑定了定时器')
    this.timer = setInterval(() => {
      this.opacity -= 0.01
      if (this.opacity <= 0) this.opacity = 1
    }, 10)
  },
  deactivated() {
    console.log('组件失活了,解绑了定时器')
    clearInterval(this.timer)
  }
}
</script>

八、history 和 hash

路由器的两种工作模式

  • hash模式
  • history模式

路径的哈希值:# 之后的参数,其中哈希值不包含在 HTTP 请求中,也即不会将这些参数发送到服务器

export default new VueRouter({
    
    
    mode: 'history',
    routes: [
      ......
    ],
})
        
// OR
        
export default new VueRouter({
    
    
    mode: 'hash',
    routes: [
      ......
    ],
})

九、路由守卫

如果使用了路由守卫,路由配置文件就需要改成下面的格式

import Vue from 'vue';
import VueRouter from "vue-router";

Vue.use(VueRouter)

const router = new VueRouter({
     
     
	......
})

export default router

1. 全局路由守卫

  • 全局前置路由守卫
  • 全局后置路由守卫

(1)简单使用

import Vue from 'vue';
import VueRouter from "vue-router";
import MyAbout from "@/components/MyAbout.vue";
import MyHome from "@/components/MyHome.vue";

Vue.use(VueRouter)

const router = new VueRouter({
    
    
	......
})



// 每次路由切换之前调用、初始化调用
router.beforeEach((to, from, next) => {
    
    
    console.log('前置', to, from, next)
    next() // 放行
})
// 每次路由切换之后调用、初始化调用
router.afterEach((to, from) => {
    
    
    console.log('后置', to, from)
})



export default router

(2)组件鉴权

判断哪个组件需要权限才可以访问

  • 在 meta 属性里面配置组件的元信息,表示组件是否需要鉴权
  • meta 属性是专门留给我们自定义属性的

声明鉴权属性

const router = new VueRouter({
    
    
    mode: 'history',
    routes: [
        {
    
    
            path: '/about',
            component: MyAbout,
            meta: {
    
    
                isAuth: true,
            }
        }, {
    
    
            path: '/home',
            component: MyHome,
            meta: {
    
    
                isAuth: false,
            }
        }
    ],
})

进行鉴权

// 每次路由切换之前调用、初始化调用
router.beforeEach((to, from, next) => {
    
    
    console.log('前置')
    if (to.meta.isAuth) {
    
    
        let isOk = true
        if (isOk) {
    
    
            console.log('需要鉴权,权限符合,放行')
            next()
        } else {
    
    
            console.log('需要鉴权,权限不符合,不放行')
        }
    } else {
    
    
        console.log('不需要鉴权,放行')
        next()
    }
})


// 每次路由切换之后调用、初始化调用
router.afterEach((to, from) => {
    
    
    console.log('后置', to, from)
})

(3)应用:修改网页标题

每次切换路由,查看组件信息时,修改网页标题,使其更符合当时的查看状态

每个组件保存一个标题

const router = new VueRouter({
    
    
    routes: [
        {
    
    
            path: '/about',
            component: MyAbout,
            meta: {
    
    
                isAuth: true,
                title: '关于'
            }
        }, {
    
    
            path: '/home',
            component: MyHome,
            meta: {
    
    
                isAuth: false,
                title: '主页'
            }
        }
    ],
})

前置路由守卫实现

router.beforeEach((to, from, next) => {
    
    
    console.log('前置')
    if (to.meta.isAuth) {
    
    
        let isOk = true
        if (isOk) {
    
    
            console.log('需要鉴权,权限符合,放行')
            next()
            document.title = to.meta.title || '默认标题'
        } else {
    
    
            console.log('需要鉴权,权限不符合,不放行')
        }
    } else {
    
    
        console.log('不需要鉴权,放行')
        next()
        document.title = to.meta.title || '默认标题'
    }
})

后置路由守卫实现

router.afterEach((to, from) => {
    
    
    console.log('后置', to, from)
    document.title = to.meta.title || '默认标题'
})

虽然配置了路由守卫修改网页标题,但是在首次加载页面时,会出现瞬间的网页标题切换的变化,根本解决办法:修改 package.json 配置文件

2. 独享路由守卫

进入当前路由之前调用,专属于当前组件的路由守卫

import Vue from 'vue';
import VueRouter from "vue-router";
import MyAbout from "@/components/MyAbout.vue";
import MyHome from "@/components/MyHome.vue";

Vue.use(VueRouter)

const router = new VueRouter({
    
    
    routes: [
        {
    
    
            path: '/about',
            component: MyAbout,
            meta: {
    
    
                isAuth: true,
                title: '关于'
            },
            beforeEnter(to, from, next) {
    
    
                console.log('前置')
                let isOk = true
                if (isOk) {
    
    
                    console.log('独享路由守卫鉴权,权限符合,放行')
                    next()
                } else {
    
    
                    console.log('独享路由守卫鉴权,权限不符合,不放行')
                }
            }
        }, {
    
    
            path: '/home',
            component: MyHome,
            meta: {
    
    
                isAuth: false,
                title: '主页'
            }
        }
    ],
})


// 每次路由切换之后调用、初始化调用
router.afterEach((to, from) => {
    
    
    console.log('后置', to, from)
    document.title = to.meta.title || '默认标题'
})


export default router

3. 组件内路由守卫

也可以把它当成钩子函数

仅当通过路由规则进入组件时调用,手动在模板里面写的组件标签不算,如下

<MyAbout></MyAbout>

简单使用

<script>
    export default {
        name:'About',
        // 通过路由规则,进入该组件时被调用
        beforeRouteEnter (to, from, next) {
            if(true){
                next()
            }else{
                alert('无权限查看!')
            }
        },
        // 通过路由规则,离开该组件时被调用
        beforeRouteLeave (to, from, next) {
            next()
        }
    }
</script>

猜你喜欢

转载自blog.csdn.net/bugu_hhh/article/details/129699107