深入了解vue-router原理并实现一个小demo

Tia ·
更新时间:2024-09-20
· 481 次阅读

目录

插件编写的基本方法

需求分析

我们先看看vue-router的使用步骤

由此我们看看vue-router内部做了什么?

实现思路

首先我们看看如何将$router挂载到组件上​

​如何实现那两个路由组件

先来看看router-link

完整demo代码

总结

插件编写的基本方法

推荐大家先看看官方给出的插件使用和开发方法

https://vuejs.bootcss.com/guide/plugins.html​

需求分析 我们先看看vue-router的使用步骤

1.use

Vue.use(VueRouter)

注意⚠️:

Vue.use()主要是调用插件内部的install方法,并将Vue实例作为参数传入​

2.new 一个router实例

const router = new VueRouter({ // 实例化router传入的参数 mode: 'history', base: process.env.BASE_URL, routes })

3.new Vue() ,把实例放在vue的配置项里面

new Vue({ router, // 注意router的实例也往里传 render: h => h(App) }).$mount('#app')

4.使用路由组件<router-view/><router-link></router-link>或者在组件中使用this.$router

由此我们看看vue-router内部做了什么?

将$router挂载到全局上实现并声明了两个组件:<router-view/><router-link></router-link>

实现思路 首先我们看看如何将$router挂载到组件上​ let Vue; // 保存vue的构造函数,避免打包将其打进去 VueRouter.install = function (_Vue) { Vue = _Vue; console.log("options", Vue.$options); Vue.mixin({ beforeCreate() { console.log("inner", this); console.log(" this.$options.router", this.$options.router); if (this.$options.router) { Vue.prototype.$router = this.$options.router; } }, }); console.log("end"); };

可以看到:

1、第一次执行的时候,即在Vue.use(Router)时,还没有实例化vue(因为Vue.use()发生在 new Vue()之前),所以Vue.$option本身是拿不到的(ps: option就是new Vue()时传入的参数,router也往里面传),此时既然拿不到router的实例,所以不能直接在install方法里面挂载;

​2、我们可以在use的时候做一个全局混入,在合适的时间点,获取到Vue根实例配置项中的router实例, 执行挂载。紧接着在new Vue()根实例创建的时候,因为注入了router实例,所以再执行全局混入(mixin)中的生命周期时,这个时候根实例的配置项this.$options已经包含了router实例,可以此时把router挂载到Vue的原型上。之后所有Vue实例扩展来的VueCompont都可以通过this.$router访问到这个属性

​如何实现那两个路由组件

先看看路由组件如何使用

<div id="app"> <div id="nav"> <!-- a标签控制跳转 --> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> </div> <!-- 路由出口 --> <router-view /> </div>

由上面可以看出,点击router-link,就相当于点了a标签,然后a标签的href属性控制页面路由发生了变化;监听路由变化,然后仔router-view里面输出不同的模板;​

先来看看router-link class VueRouter { constructor(options) { // 接受传入的参数 this.$options = options; const initial = "/"; // 将current变成响应式数据, //这样在hashchange的回掉中修改curent时, //用到current的router-view的render函数就会重新渲染 Vue.util.defineReactive(this, "current", initial); // 监听路由变化 window.addEventListener("hashchange", () => { // 获取当前url中的hash this.current = window.location.hash.slice(1); }); } } VueRouter.install = function (_Vue) { Vue = _Vue; Vue.component("router-view", { render(h) { // 获取当前路由所对应的组件,然后把它渲染出来 const { current, $options } = this.$router; // 这里要注意 我们传进来的routes是一个路由表,如下图一 // 所以这里我们是找出匹配到当前current路由的项,然后直接渲染组件 const route = $options.routes.find((item) => { return item.path === current; }); let component = route ? route.component : null; return h(component); }, }); }

​再来看看router-view

class VueRouter { constructor(options) { // 接受传入的参数 this.$options = options; const initial = "/"; // 将current变成响应式数据, //这样在hashchange的回掉中修改curent时, //用到current的router-view的render函数就会重新渲染 Vue.util.defineReactive(this, "current", initial); // 监听路由变化 window.addEventListener("hashchange", () => { // 获取当前url中的hash this.current = window.location.hash.slice(1); }); } } VueRouter.install = function (_Vue) { Vue = _Vue; Vue.component("router-view", { render(h) { // 获取当前路由所对应的组件,然后把它渲染出来 const { current, $options } = this.$router; // 这里要注意 我们传进来的routes是一个路由表,如下图一 // 所以这里我们是找出匹配到当前current路由的项,然后直接渲染组件 const route = $options.routes.find((item) => { return item.path === current; }); let component = route ? route.component : null; return h(component); }, }); }

图一

完整demo代码 // 我们要实现什么 // 1、插件 // 2、两个组件 // 保存vue的构造函数,避免打包将其打进去 let Vue; class VueRouter { constructor(options) { this.$options = options; const initial = "/"; Vue.util.defineReactive(this, "current", initial); this.current = "/"; window.addEventListener("hashchange", () => { // 获取当前url中的hash this.current = window.location.hash.slice(1); }); } } // 参数1在Vue.use()调用时传进来, VueRouter.install = function (_Vue) { Vue = _Vue; console.log("options", this); // 全局混入 // 目的:延迟下面的逻辑 到 router创建完毕并且附加到选项上时才执行 Vue.mixin({ // 在每个组件创建实例时都会执行 beforeCreate() { // this.$options.router ;即new Vue时放进去的router实例 if (this.$options.router) { Vue.prototype.$router = this.$options.router; } }, }); // 注册并且实现两个组件 Vue.component("router-link", { props: { to: { required: true, }, }, render(h) { return h( "a", { attrs: { href: "#" + this.to }, }, this.$slots.default ); }, }); Vue.component("router-view", { render(h) { // 获取当前路由所对应的组件,然后把它渲染出来 const { current, $options } = this.$router; const route = $options.routes.find((item) => { return item.path === current; }); let component = route ? route.component : null; return h(component); }, }); }; export default VueRouter; 总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注软件开发网的更多内容!     



VUE demo vue-router

需要 登录 后方可回复, 如果你还没有账号请 注册新账号