关于vue-router的一些用法以及实现原理-vue router教程

2023-08-07 20:13:15

 

以下内容为个人学习整理的笔记,后续若有不同理解,再来修改。

1、vue中路由的作用(前端路由)

vue路由针对单页应用,根据路径的hash值来匹配显示对应的组件,在单页应用模拟页面跳转。vue当中的路由 匹配的资源是我们创建的组件。

2、如何在vue中使用vue-router?

需要引入router插件,调用vue中use的方法

import Vue from vue import VueRouter from vue-router Vue.use(VueRouter)

3、实例化router,并配置router的配置对象,含routes路由;

// router.js export default new Router({ mode:"hash", //vue-router路由模式的默认方式 routes:[ { path:"/hello", component:HelloWorld }, { path:"/", component:VuexTest }, { path:"/form", component:Form } ] })

4、在vue实例上挂载router实例

// main.js import router from "./config/router"; new Vue({ router, render: h => h(App), }).$mount(#app)

5、使用

<template> <div id="app"> <router-link to="/">home</router-link>| <router-link to="/form">form</router-link>| <router-link to="/hello">HelloWorld</router-link> <router-view></router-view> </div> </template>

6、效果

点击home,form,helloWorld可以切换路由页面。

vue-router主要是做了什么?

router-link和router-view都是vue中的全局组件,他们分别用来跳转路由和展示对应路由显示的组件内容。

我们通过点击router-link导致路由改变了,vue-router内部必然是在监听路由变化,根据路由规则找到匹配的路由,然后在router-view显示对应路由的组件内容。

所以我们切换路由最终是页面的不同组件的展示,而不是页面的刷新。

那vue-router是如何监听路由变化并且切换路由的呢?

vue-router核心代码精简版

let Vue; class KVueRouter { constructor(options){ this.$options=options; this.$routerMap={};//{"/":{component:...}} // url 响应式,当值变化时引用的地方都会刷新 this.app = new Vue({ data:{ current:"/" } }); } // 初始化 init(){ // 监听事件 this.bindEvent(); // 解析路由 this.createRouteMap(); // 声明组件 this.initComponent(); } bindEvent(){ window.addEventListener(hashchange,this.onHashchange.bind(this)); } onHashchange(){ this.app.current = window.location.hash.slice(1) || "/"; } createRouteMap(){ this.$options.routes.forEach(route=>{ this.$routerMap[route.path]=route; }) } initComponent(){ Vue.component(router-link,{ props:{ to:String, }, render(h){ return h(a,{attrs:{href:#+this.to}},[this.$slots.default]) } }); Vue.component(router-view,{ render:(h)=>{ const Component = this.$routerMap[this.app.current].component; return h(Component) } }); } } // 参数是vue构造函数,Vue.use(router)时,执行router的install方法并把Vue作为参数传入 KVueRouter.install = function(_vue){ Vue = _vue; //全局混入 Vue.mixin({ beforeCreate(){//拿到router的示例,挂载到vue的原型上 if (this.$options.router) { Vue.prototype.$router=this.$options.router; this.$options.router.init(); } } }) } export default KVueRouter;

远行如下:

Vue.use(Router)时,会调用router的install方法并把Vue类传入,混入beforeCreate方法,即在Vue实例化后挂载前在vue原型上挂个$router方法(因为这样后面才能用this.$router.push()...但此处没有实现哦),然后调用router实例的init方法; 在init中把三件事情都干了,监听路由,解析路由(路由mapping匹配),定义组件; 需要注意的是,存储当前路由的变量this.app.current非一般的变量,而是借用Vue的响应式定义的,所以当路由变化时只需要给这个this.app.current赋值,而router-view组件刚好引用到这个值,当其改变时所有的引用到的地方都会改变,则得到的要展示的组件也就响应式的变化了。

路由传参的三种方式和获取路由参数、以及解决vue路由传参页面刷新参数丢失问题

1、可以通过params传参,使用this.$route.params去获取这种方式的路由参数

this.$router.push({ name:"admin", params:{id:item.id}})    //这里的params是一个对象,id是属性名,item.id是值(可以从当前组件或者Vue实例上直接取) //这个组件对应的路由配置{   //组件路径 path: /admin,   //组件别名 name: admin,   //组件名 component: Admin,}

2、路由属性配置传参

this.$router.push({ name:"/admin/${item.id}",}) //这个组件对应的路由配置{   //组件路径 path: /admin:id,   //组件别名 name: admin,   //组件名 component: Admin,}

以上两种传参方式基本上可以理解为ajax中的post请求方式,参数都是不可见的,但是上面两种方法都有一个弊端,就是当页面刷新了是获取不到参数值的。

3、query传参,使用this.$route.query去获取这种方式的路由参数

this.$router.push({ name:"/admin", query:{id:item.id}}) //这个组件对应的路由配置{   //组件路径 path: /admin,   //组件别名 name: admin,   //组件名 component: Admin,}

第三种方式是用query来传参,这种方式是可以解决页面刷新参数消失问题的,这种方式可以理解为是ajax中的get方法,参数是直接在url后面添加的,参数是可见的。

其余两个传参的方式及获取路由参数

1、设置动态路由传参,url路径显示成http://localhost:8080/#/search/1,这种是使用this.$route.params获取参数

var id = 1; this.$router.push("/admin/"+id) //这个组件对应的路由配置{   //组件路径 path: /admin/:id, 指的是动态路由传参  //组件别名 name: admin,   //组件名 component: Admin,}

2、若没有设置动态路由传参,url的路径是显示成http://localhost:8080/#/search?id=1,这种是使用this.$route.query去获取参数。

var id = 1; this.$router.push("/admin?id="+id) //这个组件对应的路由配置{   //组件路径 path: /admin, //组件别名 name: admin,   //组件名 component: Admin,}

vue-router的两种路由模式

1、hash模式(默认方式)

使用URL的hash来模拟一个完整的URL,于是当 URL 改变时,页面不会重新加载。这就是路由里带#的原因。

2、history模式

这种模式充分利用history.pushStateAPI 来完成 URL 跳转而无须重新加载页面。不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://oursite.com/user/id 就会返回 404,这就不好看了。

如果不想要很丑的 hash,通过以下方式来切换。

const router = new VueRouter({ mode: history, routes: [...] })

详情请看文章 HTML5 History 模式

什么是路由重定向?

指的是页面的重定向是使用redirect指向了某个路径,同时component对应的组件有指向了这个PersonPage组件(将一些url的访问,引导到我们希望的页面)。

var routes = [ // 页面的重定向是使用redirect指向了某个路径,同时component对应的组件有指向了这个PersonPage组件 { path: /person, component: PersonPage }, { path: /, redirect: person }, { path: /index, redirect: person } ]

如何嵌套路由?(二级路由、三级路由...)

实际生活中的应用界面,有一些由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也对应各个被嵌套的各层组件,例如:

/student/:id/profile /student/:id/posts

+------------------+ +-----------------+

| Student Name | | Student Name |

| +--------------+ | | +-------------+ |

| | Profile | | +------> | | Posts | |

| | | | | | | |

| +--------------+ | | +-------------+ |

+------------------+ +-----------------+

借助 vue-router,使用嵌套路由配置,就可以很简单地表达这种关系。

1、页面准备

以student为例

//父组件 <div id="app"> <router-link to="/student/0">学生0</router-link> <router-link to="/student/0/profile">学生0的个人信息</router-link> <router-link to="/student/0/article">学生0的个人文章</router-link> <router-view></router-view> </div> //子组件 var Student = { template: <div>学生id:{{ $route.params.id }}</div> } var routes = [ //子组件路由配置 { path: /student/:id, component: Student } ]

2、被嵌套的子组件对象

创建需要嵌套显示的子组件

var StudentProfile = { template: <div>学生个人信息:{{ $route.params.id }}</div> } var StudentArticle = { template: <div>学生个人文章:{{ $route.params.id }}</div> }

3、父组件中显示嵌套子路由的坑位

在 Student 组件的模板添加一个 <router-view>:

最外层 <div id="app"> 里面的 <router-view> 是最顶层的出口,渲染最高级路由 student/:id 匹配到的组件 Student。这个被渲染Student 同样可以包含自己的嵌套 <router-view>:
var Student = { template: `<div> 学生id:{{ $route.params.id }} <br/> <router-view></router-view> </div>` }

4、设置子路由配置

要在嵌套的出口中渲染组件,需要在 VueRouter 的参数中使用 children 配置:

routes = [ { path: /student/:id, component: Student, // 嵌套路由,使用children的属性,也是一个数组,数组里面是配置对象,也是path+component组合 children: [ { path: profile, component: StudentProfile }, { path: article, component: StudentArticle } ] } ] // 当 /student/:id/profile 匹配成功, // StudentProfile 会被渲染在 Student 的 <router-view> 中

注意:子路由的路径前面不能带斜杠,因为以 / 开头的嵌套路径会被当作根路径。

5、嵌套路由小结

嵌套路由显示嵌套子组件的方法

在父组件当中挖一个坑,其实就是 router-view 标签,准备放嵌套的子组件创建需要被嵌套的子组件在路由配置,父组件的配置对象当中,插入 children 属性,是一个数组,里面可以放入子路由配置对象子路由对象跟父路由对象设置的属性基本一致嵌套路由目的是通过 url 控制 父组件中的嵌套子组件显示,特点是每一个子组件显示都是在父组件当中,这个父组件一直不变,包裹着跟随 url 变化的 子组件

*若想嵌套三级路由,同理,需要在跳转的组件中添加children...

路由属性和额外元信息

1、路由属性

route: 单个路由信息,通常都是指当前页面的路由信息

routes: 复数,多个路由,用来路由配置当中

router: 后缀 er 其实就是xxx工作的人的意思,router的值是管理整个路由的实例对 象,保存了所有配置,提供了方法和必要的组件。

this.$route存储了当前页面的所有路由信息, 包括参数, 路径等等

有两个需要额外介绍的内容

matched 当前的 url 在匹配路由是, 符合要求的记录, 是一个数组, 如果是嵌套路由, 就会从第一层到最后一层都存放在里面meta 元数据 在路由配置当中有一个 meta 元数据属性, 可以供我们自由使用, 默认是一个空对象, 但是可以存放各种类型的数据, 通常用在辨识是否需要权限校验, 给页面添加描述输出面包屑

2、嵌套路由面包屑案例

目标:在嵌套路由的基础上,实现一个面包屑功能。切换嵌套子组件显示的时候,改变面包屑的显示,同时面包屑可以点击返回上一级。

技术基础:在组件里面可以拿到路由信息, this.$route, 里面有匹配的嵌套 matched 和 可以随意添加的 元数据 meta

步骤:

路由配置当中,为路由添加 meta 属性,提供可读标题监听路由变化,mounted 只会触发一次所以不行,要用 watchwatch 当中遍历数据 this.$route.matched,逐层累加 meta 数据形成面包屑将生成的面包屑赋值到 data 渲染出来
<div id="app"> <div id="menu"> <router-link to="/student?id=0">学生0</router-link> <router-link to="/student/post?id=0">学生0的文章</router-link> <router-link to="/student/comment?id=0">学生0的评论内容</router-link> </div> <!-- 4、在模板当中,使用路由默认的标签,指定渲染组件的位置(坑位) --> <router-view></router-view> </div> <script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script> <!-- 引入路由 --> <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.2.0/vue-router.js"></script> <script> // this.$route主要用于获取路由对象 // 学生0的局部组件 var StudentPage = { // <div>学生{{students[$route.query.id].name}}</div> template: ` <div> <div> <span v-for="(item,index) in breadmeta"> {{item}} </span> </div> 学生{{studentActive.name}}<br> <router-view></router-view> </div> `, data() { return { breadmeta: [], students: [ { name: tom, age: 18 } ] } }, // 计算属性过滤学生信息 computed: { studentActive() { return this.students[this.$route.query.id] } }, mounted() { console.log(this.$route); // 面包屑第三步, 加载完和路由发生变化的时候都要触发计算 this.getBreadMeta() }, //监听路由变化 watch: { $route() { this.getBreadMeta() } }, methods: { getBreadMeta() { console.log(this.$route.matched); var breadmeta = []; this.$route.matched.forEach(ele => { breadmeta.push(ele.meta); }) this.breadmeta = breadmeta } } } // 学生0的文章局部组件 var StudentPost = { template: ` <div>文章内容</div> ` } // 学生0的文章评论 var StudentComment = { template: ` <div>文章评论</div> ` } // 2、创建路由配置,是一个数组 var routes = [ { path: /student, component: StudentPage, meta: 学生首页, children: [ { path: post, component: StudentPost, meta: 学生文章 }, { path: comment, component: StudentComment, meta: 学生评论 } ] }, ] // 3、创建路由实例 var router = new VueRouter({ // 带上路由配置 // es6语法,key与vlaue相同,可以省略,只写一个 // 业内习惯写routes routes }) // vue实例 var app = new Vue({ el: "#app", data: { showPage: login }, // router: router // 把路由挂载到根实例中 router }) </script>

如果需要把编程式导航变为点击后可以跳转的链接,需要如下操作:

1、把学生0的局部组件模板进行修改

template: ` <div> <div> <router-link v-for="(item,index) in breadmeta" :to="item.path" :key="index"> {{item.meta}} </router-link> </div> 学生{{studentActive.name}}<br> <router-view></router-view> </div> `,

2、对methods中getBreadMeta函数进行修改

methods: { getBreadMeta() { var studentId = this.$route.query.id; console.log(studentId); var breadmeta = []; this.$route.matched.forEach(ele => { breadmeta.push({ meta: ele.meta, path: ele.path + ?id= + studentId }); }) this.breadmeta = breadmeta } }

3、设置完这两步之后就可以在点击编程式导航的时候跳转路由,控制组件的显示了

vue-router中的路由懒加载是如何实现的?

1、可以通过异步组件的方式(vue-router中配置路由),按需加载

2、es提案的import( )

3、webpack的require.ensure( )

vue-router中的路由拦截

1、路由拦截,需要在定义路由的时候添加一个自定义字段requireAuth,用于判断该路由的访问是否需要登录。

2、主要是利用vue-router提供的钩子函数beforeEach()对路由进行判断。

router.beforeEach((to, from, next) => { if (to.meta.requireAuth) { // 判断该路由是否需要登录权限 if (store.state.token) { // 通过vuex state获取当前的token是否存在 next(); } else { next({ path: /login, query: {redirect: to.fullPath} // 将跳转的路由path作为参数,登录成功后跳转到该路由 }) } } else { next(); } })

3、钩子函数beforeEach的上参数的含义如下:

to: Route: 即将要进入的目标 路由对象

from: Route: 当前导航正要离开的路由

next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。

next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。

next(false): 中断当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

next(‘/’) 或者 next({ path: ‘/’ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。


以上就是关于《关于vue-router的一些用法以及实现原理-vue router教程》的全部内容,本文网址:https://www.7ca.cn/baike/60029.shtml,如对您有帮助可以分享给好友,谢谢。
标签:
声明

排行榜