最近学习了vue,然后简单的了解了下vue-router,现在简单的写一个简单版的vue-router进行源码分析。这是vue-router基本用法vue-router基本用法vue的生命周期官网给出了很棒的https://cn.vuejs.org/images/l...安利首先我们需要了解:插件、插槽、混合-ins,renderfunction,runtime和完整版的vue首先我们用vue-cli创建一个项目,我们需要使用带编译器的版本,因为模板需要编译。然后我们找到对应的router/index.js,将官方的vue-router换成我们新的//importVueRouterfrom'vue-router'importVueRouterfrom'../../Vue-router'路由接口配置constroutes=[{path:'/',name:'Index',component:Index},{path:'/login',name:'Login',//路由级代码拆分//这会生成一个单独的块(关于.[hash].js)forthisroute//在访问路由时延迟加载。component:()=>import(/*webpackChunkName:"about"*/'../views/Login.vue')},{path:'/detail/:id',name:'Detail',props:true,component:()=>import(/*webpackChunkName:"detail"*/'../views/Detail.vue')}]constrouter=newVueRouter({routes})app.vueinterface我们简单设置一下然后开始考虑Vue.use(VueRouter)传入对象的install方法会在注册的插件内部调用。本节主要是vue-router文件中core的主要实现思路是:创建一个VueRouter类并添加一个判断插件是否加载的静态方法,不要重复加载记录Vue构造函数.Vue加载时,将传入的路由器对象挂载到Vue原型上。(只执行一次,使用mixed-in方法)在VueRouter中创建具体方法初始化,options,routeMap,data(当前路由,响应数据)createRouteMap生成路由信息的map,放在routeMap中initComponent用来创建路由的组件router-link和router-viewinitEvent监听浏览器的事件哈希或历史记录。下面是具体实现let_Vue=nullclassVueRouter{staticinstall(Vue){//1判断当前插件是否安装if(VueRouter.install.installed){return}VueRouter.install.installed=true//installed//2在全局中记录Vue的构造函数_Vue=Vue//3在第一次创建Vue实例时传入router对象,也就是实例化VueRouter对象,//vue会把router放在$options上被实例化后,我们获取它并将其注入到Vue原型中,然后再将其混合到生命周期中,以便于使用//所有vue实例内部都使用this.$router可以访问_Vue.mixin({beforeCreate(){if(this.$options.router){console.dir(this)_Vue.prototype.$router=this.$options.router}}})}constructor(options){this.options=options//在实例化路由时存储参数。this.routeMap={}//路由对应的映射,组件this.historyMode=options.mode==='history'this.data=_Vue.observable({//创建一个可观察的,响应式的数据current:'/'})this.init()//初始化路由信息}init(){this.createRouteMap()//创建Mapping信息this.initComponent(_Vue)//创建并使用组件router-linkrouter-viewthis.initEvent()//监听浏览器点击左右历史popstate事件}createRouteMap(){//遍历所有路由规则,解析路由rulesintokeyvaluespair的形式存储在routeMap中this.options.routes.forEach(route=>{this.routeMap[route.path]=route.component//值为对应的组件})}initComponent(Vue){//创建路由组件constthat=thisconstrouterLinkOption={props:{to:String//设置router-linkprops跳转地址必须为字符串},render(h){//设置组件的render函数,不懂vuerender执行时,可以看到它的生命周期conston={};lethref=`#${this.to}`if(that.historyMode){on.click=this.clickhanderhref=this.to}returnh('a',{//h函数生成虚拟dom属性:{//setattributehref},on//event},[this.$slots.default])//最后,组件中的子元素,我们通过slot获取到}}if(that.historyMode){routerLinkOption.methods={clickhander(e){//组件方法e.preventDefault()//防止默认跳转turntohistory.pushState({},'',this.to)//更改历史模式下的url地址,不发送请求this.$router.data.current=this.to//更改的值observable对象,触发响应式观察Updater}}}Vue.component('router-link',routerLinkOption)Vue.component('router-view',{//viewdisplaycomponentrender(h){console.log(that.data.current)constcm=that.routeMap[that.data.current]//获取路由对应的组件returncm?h(cm):h('div','404')//传给hfunction,它会帮我们转换成virtualdom}})}initEvent(){//初始化浏览器前向和后向事件拦截letloadCb=nullif(this.historyMode){this.historyInitEvent()loadCb=this.historyChangeHandler}else{this.hashInitEvent()loadCb=this.hashChangeHandler}window.addEventListener('load',loadCb)}historyInitEvent(){window.addEventListener('popstate',this.historyChangeHandler)}historyChangeHandler=()=>{//拦截t,使用箭头函数thisthis.data.current=window.location.pathname//改变observable对象,触发router-viewupdate}hashChangeHandler=()=>{this.data.current=window.location.hash.substr(1)||}'/'}hashInitEvent(){window.addEventListener('hashchange',this.hashChangeHandler)}}exportdefaultVueRouter主要核心代码在这个vue-router文件中。这只是一个简单的版本。它只是模仿。运行vue-router看看效果。本内容借用拉勾前端训练营
