自定义插件vue-router简单实现hashRouter设计思路

本文主要是介绍自定义插件vue-router简单实现hashRouter设计思路,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

步骤

1.挂载 vue.prototype.$router

2.声明两个组件

router-view this.$router.current=>component => h(component)

router-link h('a',{attrs:{href:'#'+this.to}},this.$slots.default)

3.url的监听:window hashchange的改变

4.定义响应式current,defineReactive()

实现VueRouter类

let Vue
// vueRouter是一个类,一个插件
class VueRouter {constructor(options) {this.$options = options}
}VueRouter.install = function (_Vue) {//保存引用Vue = _Vue//挂在一下vueRouter到vue原型//利用全局混入,全局执行代码,在vue实例beforeCreate时获取到router,因为在main.js中生成vue实例在VueRouter挂载到Vue之后,所以常规无法获取到router,Vue.mixin({beforeCreate() {if (this.$options.router) { //避免每次实例创建都触发,只有根实例上存在的才触发。Vue.prototype.$router = this.$options.router}}})//声明两个全局组件,router-viewport,router-linkVue.component('router-link', {props: {to: {type: String,required: true}},//预编译情况下,template是不能使用的,这里要使用render// template:'<a>123</a>'render(h) {// return <a href={'#'+this.to}>{this.$slots.default}</a> jsx语法也可以使用return h('a', {attrs: { href: "#" + this.to }}, this.$slots.default) //this.$slots.default 获取内容}})Vue.component('router-view', {render(h) {return h('div', 'router-view')}})
}export default VueRouter

这里有个难点,就是如何将router挂载到vue原型上,我们采用了mixin的用法,在vue实例beforeCreate时获取到router,并挂在到实例上。

怎么理解呢?在router.js中,Vue.use(VueRouter)触发install方法,但是在此时,并没有生成router,是在new VueRouter之后生成的router,并且挂载到了Vue,此时才有VueRouter,利用全局混入,延迟执行挂载到Vue原型上,这样就可以获取到router实例了。

import Vue from 'vue'
// import VueRouter from 'vue-router'
import VueRouter from '@/krouter/kvue-router'
Vue.use(VueRouter)//执行install方法,router还未被创建
const routes = [{path: '/home',name: 'home',component: () => import('@/components/Home.vue')},{path: '/about',name: 'about',component: () => import('@/components/About.vue')},
]const router = new VueRouter({routes
})
export default router
import Vue from 'vue'
import App from './App.vue'
import router from './router/router'Vue.config.productionTip = falsenew Vue({router,render: h => h(App),
}).$mount('#app')

监听url变化,渲染组件

class VueRouter {constructor(options) {this.$options = options//声明一个响应式current//渲染函数如果压重复执行,必须依赖响应式数据Vue.util.defineReactive(this,'current',window.location.hash.slice(1) || '/') //需要#后面的部分//监听url变化window.addEventListener('hashchange', () => {this.current = window.location.hash.slice(1)})}
}

这里使用Vue工具类定义响应式current,必须是响应式current,否则不生效,在router-view处读取并渲染对应组件,在这里Vue的原型对象已经挂载了this.$router,this.$router又是VueRouter的实例,所以在这上面能够找到对应的current属性,所以在current变化的时候,在引用到current的地方都会被通知到,然后渲染组件。

Vue.component('router-view', {render(h) {const obj = this.$router.$options.routes.find(el=>this.$router.current==el.path)return h(obj.component)}})

但是每次都要去遍历循环字典,也不是很合理,我们可以优化一下,缓存一下path和route映射关系

路由嵌套

思路:参考源码思路,给当前routerView深度标记,然后根据当前页面路由获取当前路由数组,其中包括一级和二级路由,然后使用depth获取对应的组件,然后并渲染。

Vue.component('router-view', {render(h) {//标记当前router-view深度this.$vnode.data.routerView = truelet depth = 0let parent = this.$parentwhile (parent) {const vnodeData = parent.$vnode && parent.$vnode.dataif (vnodeData) {if (vnodeData.routerView) {//说明当前的parent是一个routerViewdepth++}}parent = parent.$parent}let component = nullconst route = this.$router.matched[depth]if (route) {component = route.component}return h(component)}})

此时我们不再使用current来做响应式,使用matched数组获取匹配关系,VueRouter实例创建时调用match方法,获取路由数组,并且在路由发生变化时重新获取路由数组matched。

class VueRouter {constructor(options) {this.$options = options//声明一个响应式current//渲染函数如果压重复执行,必须依赖响应式数据// Vue.util.defineReactive(this,'current',window.location.hash.slice(1) || '/') //需要#后面的部分this.current = window.location.hash.slice(1) || '/' //初始值Vue.util.defineReactive(this, 'matched', [])// match方法可以递归的遍历路由表获取匹配关系的数组this.match()//监听url变化window.addEventListener('hashchange', () => {this.current = window.location.hash.slice(1)this.matched=[]this.match()})}match(routes) {routes = routes || this.$options.routesconsole.log(routes);//递归遍历路由表for (const route of routes) {if (this.current.indexOf(route.path)!=-1) {this.matched.push(route)if (route.children) {this.match(route.children)}return}}}
}

附完整代码:

//vue-router插件
let Vue
// vueRouter是一个类,一个插件
class VueRouter {constructor(options) {this.$options = options//声明一个响应式current//渲染函数如果压重复执行,必须依赖响应式数据// Vue.util.defineReactive(this,'current',window.location.hash.slice(1) || '/') //需要#后面的部分this.current = window.location.hash.slice(1) || '/' //初始值Vue.util.defineReactive(this, 'matched', [])// match方法可以递归的遍历路由表获取匹配关系的数组this.match()//监听url变化window.addEventListener('hashchange', () => {this.current = window.location.hash.slice(1)this.matched=[]this.match()})}match(routes) {routes = routes || this.$options.routes//递归遍历路由表for (const route of routes) {if (this.current.indexOf(route.path)!=-1) {this.matched.push(route)if (route.children) {this.match(route.children)}return}}console.log(this.matched);}
}VueRouter.install = function (_Vue) {//保存引用Vue = _Vue//挂在一下vueRouter到vue原型//利用全局混入,全局执行代码,在vue实例beforeCreate时获取到router,因为在main.js中生成vue实例在VueRouter挂载到Vue之后,所以常规无法获取到router,Vue.mixin({beforeCreate() {if (this.$options.router) { //避免每次实例创建都触发,只有根实例上存在的才触发。Vue.prototype.$router = this.$options.router}}})//声明两个全局组件,router-viewport,router-linkVue.component('router-link', {props: {to: {type: String,required: true}},//预编译情况下,template是不能使用的,这里要使用render// template:'<a>123</a>'render(h) {// return <a href={'#'+this.to}>{this.$slots.default}</a> jsx语法也可以使用return h('a', {attrs: { href: "#" + this.to }}, this.$slots.default) //this.$slots.default 获取内容}})Vue.component('router-view', {render(h) {//标记当前router-view深度this.$vnode.data.routerView = truelet depth = 0let parent = this.$parentwhile (parent) {const vnodeData = parent.$vnode && parent.$vnode.dataif (vnodeData) {if (vnodeData.routerView) {//说明当前的parent是一个routerViewdepth++}}parent = parent.$parent}let component = nullconsole.log(this.$router.matched);const route = this.$router.matched[depth]if (route) {component = route.component}return h(component)}})
}export default VueRouter
import Vue from 'vue'
// import VueRouter from 'vue-router'
import VueRouter from '@/krouter/kvue-router'
Vue.use(VueRouter)//执行install方法,router还未被创建
const routes = [{path: '/home',name: 'home',component: () => import('@/components/Home.vue')},{path: '/about',name: 'about',component: () => import('@/components/About.vue'),children: [{path: '/about/info',component: {render(h) {return h('div', 'info page')}}}]},
]const router = new VueRouter({routes
})
export default router

这篇关于自定义插件vue-router简单实现hashRouter设计思路的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/462818

相关文章

使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)

《使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)》在现代软件开发中,处理JSON数据是一项非常常见的任务,无论是从API接口获取数据,还是将数据存储为JSON格式,解析... 目录1. 背景介绍1.1 jsON简介1.2 实际案例2. 准备工作2.1 环境搭建2.1.1 添加

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

java如何分布式锁实现和选型

《java如何分布式锁实现和选型》文章介绍了分布式锁的重要性以及在分布式系统中常见的问题和需求,它详细阐述了如何使用分布式锁来确保数据的一致性和系统的高可用性,文章还提供了基于数据库、Redis和Zo... 目录引言:分布式锁的重要性与分布式系统中的常见问题和需求分布式锁的重要性分布式系统中常见的问题和需求

SpringBoot基于MyBatis-Plus实现Lambda Query查询的示例代码

《SpringBoot基于MyBatis-Plus实现LambdaQuery查询的示例代码》MyBatis-Plus是MyBatis的增强工具,简化了数据库操作,并提高了开发效率,它提供了多种查询方... 目录引言基础环境配置依赖配置(Maven)application.yml 配置表结构设计demo_st

python使用watchdog实现文件资源监控

《python使用watchdog实现文件资源监控》watchdog支持跨平台文件资源监控,可以检测指定文件夹下文件及文件夹变动,下面我们来看看Python如何使用watchdog实现文件资源监控吧... python文件监控库watchdogs简介随着Python在各种应用领域中的广泛使用,其生态环境也

el-select下拉选择缓存的实现

《el-select下拉选择缓存的实现》本文主要介绍了在使用el-select实现下拉选择缓存时遇到的问题及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录项目场景:问题描述解决方案:项目场景:从左侧列表中选取字段填入右侧下拉多选框,用户可以对右侧

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要

Python pyinstaller实现图形化打包工具

《Pythonpyinstaller实现图形化打包工具》:本文主要介绍一个使用PythonPYQT5制作的关于pyinstaller打包工具,代替传统的cmd黑窗口模式打包页面,实现更快捷方便的... 目录1.简介2.运行效果3.相关源码1.简介一个使用python PYQT5制作的关于pyinstall

使用Python实现大文件切片上传及断点续传的方法

《使用Python实现大文件切片上传及断点续传的方法》本文介绍了使用Python实现大文件切片上传及断点续传的方法,包括功能模块划分(获取上传文件接口状态、临时文件夹状态信息、切片上传、切片合并)、整... 目录概要整体架构流程技术细节获取上传文件状态接口获取临时文件夹状态信息接口切片上传功能文件合并功能小

python实现自动登录12306自动抢票功能

《python实现自动登录12306自动抢票功能》随着互联网技术的发展,越来越多的人选择通过网络平台购票,特别是在中国,12306作为官方火车票预订平台,承担了巨大的访问量,对于热门线路或者节假日出行... 目录一、遇到的问题?二、改进三、进阶–展望总结一、遇到的问题?1.url-正确的表头:就是首先ur