当前位置: 首页 > Web前端 > vue.js

简易版Vue-Router源码实现了

时间:2023-03-31 14:20:09 vue.js

Vue-Router的两种模式。哈希方式1、哈希是URL中#后面的部分。2、如果网页的URL有hash,页面会定位到id和hash相同的元素,也就是锚点。3.当hash发生变化时,不会重新加载页面,会触发hashchange事件,同时也会记录在浏览器中4.vue-router的hash方式在浏览器的历史记录中主要是为了通过监听hashchange事件,根据hash值找到对应的组件进行渲染(源码会先判断浏览器是否支持popstate事件,如果支持,则通过监听popstate事件,如果不支持,监听hashchange事件)历史模式1.通过history.pushState修改页面地址2.当历史改变时,会触发popstate事件,所以可以通过监听popstate事件获取路由地址3.根据查找到路由地址使用vue-router渲染对应的组件1.注册vue-router插件importVueRouterfrom'vue-router'//注册VueRouter插件//Vue.use方法//1.如果方法传入,调用passedinMethod//2.如果传入一个对象,会调用插件的install静态方法,传入Vue的构造函数Vue.use(VueRouter)2.创建Router实例//创建路由表constroutes=[{path:'/home',component:Home,},{path:'/about',component:About,},]//实例化路由对象constrouter=newVueRouter({mode:'hash',routes})3.在Vue实例上挂载路由器实例//在实例化Vue时,在实例上注册路由器对象newVue({render:h=>h(App),router}).组件中使用$mount('#app')//通过这个获取路由对象的概要.$router,VueRouter需要做以下事情1.实现install静态方法2.根据传入的路由配置、生成对应的路由映射3、将router实例挂载到Vue实例4、注册全局组件,router-view组件通过当前url找到对应的组件进行渲染,并且当url变化时,重新渲染组件,router-link被渲染为一个标签5.通过currentUrl变量保存当前url,使数据响应6.监听hashchange或popState事件,重新渲染浏览器记录变化时router-view组件代码实现letVueConstructor=nullexportdefaultclassMyVueRouter{staticinstall(Vue){/*1.保存Vue构造函数2.在Vue实例上挂载$router实例3.注册全局componentsand*///判断安装是否已经执行if(MyVueRouter.installed){return}MyVueRouter.installed=true//1保存Vue构造函数VueConstructor=Vue//2.通过globalmixing方法,在Vue实例中mount$routerinstance//install执行时,Vue还没有实例化,所以mixinVue实例化时挂载路由器//因为是全局mix-in,需要挂载路由器判断是否为根实例Vue.mixin({beforeCreate(){//只有根实例需要挂载$router,component不需要执行if(this.$options.router){//newVue(options)时,router对象已经保存在$options中,所以可以得到console.log('this.$options.router==',this.$options.router)Vue.prototype.$router=this.$options.router}},})//3.注册全局组件//Vue.component('router-link',{props:{to:{type:String,required:true,},},methods:{clickHandler(e){if(this.$router.$options.mode==='history'){//history通过pushState改变地址,防止默认行为console.log('historymode')history.pushState({},'',this.to)this.$router._data.currentUrl=this.toe.preventDefault&&e.preventDefault()}}},render(h){returnh('a',{attrs:{href:'#'+this.to,},on:{click:this.clickHandler}},这个.$slots.default)},})Vue.component('router-view',{render(h){const{routesMap,_data}=this.$routerconstcomponent=routesMap[_data.currentUrl]console.log('component==',component)returnh(component)},})}constructor(options){/*1.保存配置选项2.获取路由映射,通过hash得到对应的组件3.设置响应变量currentUrl,保存当前的url4.监听hashchange事件。hash变化时,同时改变currentUrl*///1.保存配置选项this.$options=options//2.获取路由映射,通过hash可以得到对应的组件this.routesMap={}this.$options.routes.forEach((route)=>{this.routesMap[route.path]=route.component})console.log('routesMap===',this.routesMap)//3.设置响应变量currentUrl保存当前urlthis._data=VueConstructor.observable({currentUrl:'/',})//4.监听popstate或hashchange事件。hash变化时,同时改变currentUrl//如果浏览器支持popstate,监听popstate,不支持hashchangewindow.addEventListener('hashchange',()=>{this._data.currentUrl=window.location.hash.slice(1)console.log('this.currentUrl==',this._data.currentUrl)})}}源码实现思路因为vue.use方法会调用install静态方法,传入vueconstructor,可以在install方法中保存Vue的constructor,使VueRouter在内部,Vue也可以通过VueRouter.installed来判断插件是否已经安装。如果已安装,则无需通过Vue.mixin再次执行安装。Vue实例化时,在beforeCreate生命周期中,挂载Vue原型加载路由器对象Vue.prototype.$router=router,这里只需要挂载根实例,组件不需要挂载。使用$options.router判断是否为注册router-view的根实例,router-link全局组件router-view,根据当前url在路由表中找到对应的组件,渲染并重新渲染当前网址更改。当前url可以通过响应变量保存。路由器链接呈现为标签。如果是history模式,点击时通过history.pushState更改浏览器记录,并阻止a标签的默认行为,防止页面被刷新。在VueRouter的构造函数中,保存路由配置,传入路由通过表生成路由映射,通过变量currentUrl保存当前url,并将currentUrl设置为Vue的响应变量,以便Vue帮助收集依赖,而router-view通过依赖currentUrl获取对应的组件,这样当currentUrl发生变化时,route-view会重新渲染监听浏览器的popstate事件,当url发生变化时,currentUrl重新设置值(hash模式如果浏览器没有不支持popstate,听hashchange)