浅析vue

您所在的位置:网站首页 vuerouteview 浅析vue

浅析vue

2023-03-31 20:10| 来源: 网络整理| 查看: 265

前言

通过B站视频和一些童鞋的文章结合GitHub源码阅读来理解路由的实现原理

看过前章vuex状态管理的分享之后,相信对路由这块也是非常感兴趣的,同样的模式,同样的方式,我们走进GitHub之vue-router

同样直接走进 src在这里插入图片描述

components:route-link 组件 和 router-view 组件 实现 history:关于浏览器相关,包含 hash模式 , basic模式 ,html5模式 以及非浏览器模式以及go 、push 、replace 、back 等各自的处理方法 util:不用多说,各种工具方法 create-mathcher: 这个就比较重要的了,创建路由的匹配和添加路由配置项的方法 create-mathcher-map:跟创建路由匹配直接相关,创建路由映射map表,并封装route对象 index: 入口文件,也是vueRouter构造函数实体,原型上定义了 go 、push 、replace 、back 等 install:初始化

老样子,Vue.use(“vue-router”) 会直接执行 install 初始化进行安装插件,这里我就不多做解释了,不太理解的童鞋可以去前章看一下简单的介绍。

src/index.js 代码最后片段

VueRouter.install = install VueRouter.version = '__VERSION__' if (inBrowser && window.Vue) { window.Vue.use(VueRouter) // 进行初始化和安装路由插件 }

src/install.js 代码不多,简单看一下

import View from './components/view' // 导入router-view import Link from './components/link' // 导入router-link export let _Vue export function install (Vue) { // vue 是根实例 if (install.installed && _Vue === Vue) return install.installed = true _Vue = Vue const isDef = v => v !== undefined const registerInstance = (vm, callVal) => { let i = vm.$options._parentVnode if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) { i(vm, callVal) } } Vue.mixin({ // 类似 vuex 通过 vue.mixin 在生命周期创建前,将 router 挂载在vue根实例上 beforeCreate () { if (isDef(this.$options.router)) { this._routerRoot = this this._router = this.$options.router this._router.init(this) Vue.util.defineReactive(this, '_route', this._router.history.current) // 响应式监听 } else { this._routerRoot = (this.$parent && this.$parent._routerRoot) || this } registerInstance(this, this) // 注册实例 }, destroyed () { registerInstance(this) // 销毁实例 } }) Object.defineProperty(Vue.prototype, '$router', { // 挂载到原型上 get () { return this._routerRoot._router } }) // 这里通过 Object.defineProperty 定义 get 来实现 //而不使用 Vue.prototype.$router = this.this._routerRoot._router。是为了让其只读,不可修改 Object.defineProperty(Vue.prototype, '$route', { // 挂载到原型上 get () { return this._routerRoot._route } }) Vue.component('RouterView', View) // 注册全局组件 Vue.component('RouterLink', Link) // 注册全局组件 const strats = Vue.config.optionMergeStrategies // use the same hook merging strategy for route hooks strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created }

好了,install 初始化写的很清楚,跟 vuex 非常相似,都是安装,注册相关组件,通过mixin在生命周期创建前将实例挂载在vue根实例上。

走进核心src/index.js vueRouter 构造函数 代码量较大,分块解析

根据mode确定模式

// constructor 里 通过 mode 来判断时哪一种模式, 默认 hash let mode = options.mode || 'hash' // 是否支持 history 模式 this.fallback this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false if (this.fallback) { // 不支持则默认使用 hash mode = 'hash' } if (!inBrowser) { // 非浏览器操作,对应目录history里边的非浏览器模式 mode = 'abstract' } this.mode = mode switch (mode) { // 对应的模式做不同的处理 case 'history': this.history = new HTML5History(this, options.base) break case 'hash': this.history = new HashHistory(this, options.base, this.fallback) break case 'abstract': this.history = new AbstractHistory(this, options.base) break default: if (process.env.NODE_ENV !== 'production') { assert(false, `invalid mode: ${mode}`) } }

通过常用路由跳转方式push来分析整个流程

src/index.js vueRouter 构造函数 push 一目了然,可以看出来在这里基本什么都没有操作,只是做了一个转发,给到history 模块了

push (location: RawLocation, onComplete?: Function, onAbort?: Function) { // $flow-disable-line if (!onComplete && !onAbort && typeof Promise !== 'undefined') { return new Promise((resolve, reject) => { this.history.push(location, resolve, reject) }) } else { this.history.push(location, onComplete, onAbort) } }

hash.js 之 push

// 50 行 push (location: RawLocation, onComplete?: Function, onAbort?: Function) { const { current: fromRoute } = this this.transitionTo( location, route => { pushHash(route.fullPath) handleScroll(this.router, route, fromRoute, false) onComplete && onComplete(route) }, onAbort ) } // 切换路由 141行 对应方法 pushHash function pushHash(path) { if (supportsPushState) { pushState(getUrl(path)); } else { window.location.hash = path; } }

html5.js 之 push

// 44 行 push (location: RawLocation, onComplete?: Function, onAbort?: Function) { const { current: fromRoute } = this this.transitionTo(location, route => { pushState(cleanPath(this.base + route.fullPath)) handleScroll(this.router, route, fromRoute, false) onComplete && onComplete(route) }, onAbort) } //切换路由 8行,pushState 对应方法在工具方法里边 import { pushState, replaceState, supportsPushState } from '../util/push-state'

列举两种模式炸眼一看,大同小异呀,都是调用 this.transitionTo 方法,唯一的区别就是一个调用 pushHash , 一个调用 pushState. 不同的处理方式 。

注释:其他的 go 、 replace 、ensureURL 、getCurrentLocation 等都是同样的实现方式

好,路由核心的实现方式已经大概了解了,那么路由的匹配规则在这里简单介绍一下,我也没有继续深入了哈,毕竟只是一个匹配规则,我们走进 createMatcher 创建匹配器方法

src/create-matcher.js 16 行

export function createMatcher( routes: Array, // route 对象 router: VueRouter // 当前路由实例 this ): Matcher { // 创建路由映射 createRouteMap 重点,重点,重点方法 const { pathList, pathMap, nameMap } = createRouteMap(routes); // 匹配规则 function match(...){...} /* 匹配规则方法,根据路径来匹配路由,并创建路由对象 route , 也就是我们后来使用到的 this.$route 然后就是 create-matcher-map 创建映射关系表了,类似 {"/home":Home} 等于 { path:component} 根据path hash路径来映射对应的组件 */

当然有兴趣的童鞋可以通过珠峰公开课来进一步了解具体的实现方式,赋地址 珠峰公开课vuex+vue-router



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3