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

手写vue-router

时间:2023-03-31 20:07:01 vue.js

vue-router原理分析大家想必都不陌生,这个简单,直接引用即可。但是我们一定要抱着知其然、知其所以然的态度,今天就带大家手动实现vue-router。简介VueRouter是Vue.js的官方路由管理器。它与Vue.js的核心深度集成,可以轻松构建单页应用程序。包含的功能包括:嵌套路由/视图表模块化、基于组件的路由配置路由参数、查询、通配符基于Vue.js转换系统的视图转换具有自动激活的CSS类的细粒度导航控件自动链接HTML5历史模式或哈希模式在IE9下降级自定义滚动条行为应用步骤首先安装:vue添加路由器第一步:一般参考路由器文件夹索引文件中的路由器插件importRouterfrom'vue-router'Vue.use(Router)这里有个小问题,为什么要用use方法,因为vueRouter是一个插件,必须要用use方法才能在Vue中使用插件。第二步:创建一个Router实例,router.jsexportdefaultnewRouter({...})第三步:将实例添加到根组件,main.jsimportrouterfrom'./router'newVue({router,}).$mount("#app")第四步:添加路由视图,App.vue,这样vue-router就可以使用了,下面两个问题展开。this.$router可以访问Router实例,可以直接使用router-view和router-link这两个全局组件。那么分析一下就可以知道,插件被引用之后,相当于在原型模式下全局注册了$router方法,而Vue.prototype.$router内部必须注册,两个全局变量是同时注册。上面的手写vue-router简单介绍了vur-router的使用方法。接下来我们手动实现vue-router的源码。首先我们要分析一下vue-router是干什么的。1.作为插件存在:实现VueRouter类和install方法。2、实现两个全局组件:router-view用于显示匹配组件的内容,router-link用于跳转。3、监听url变化:监听hashchange或者popstate事件。4、响应最新的url:创建一个响应属性current,当它发生变化时,获取对应的组件并显示。1.创建一个vue-router.js文件,编写核心代码//引用构造函数,让Vue在VueRouter中使用;//保存选项,VueRouterclass:newVueRouter({routes:[...]})classVueRouter{constructor(options){this.$options=options;}}//插件:实现install方法,注册$router//Vue构造函数,Vue.use(VueRouter)VueRouter.install=function(_Vue){//引用构造函数,Vue=_Vue应该在VueRouter中使用;//任务一:挂载$router//为了能够在Vue根实例中获取router实例//可以使用全局mixinVue.mixin({beforeCreate(){//只有根组件有路由器选项if(this.$options.router){//context已经是一个组件实例Vue.prototype.$router=this.$options.router;}}});//任务2:实现两个全局组件router-link和router-viewVue.component('router-link',Link)Vue.component('router-view',View)};导出默认VueRouter;上面的代码有几个问题可以一起讨论,为什么一开始就定义一个变量Vue,而不是引入一个真正的Vue。大家都知道Vue.mixin和Vue.component是Vue类的方法。Vue-Router要想使用它,就必须引入Vue.这个大家都知道,但是如果把Vue打包到Vue-router的源码里面,那肯定会导致Vue-router的包变得很大。为什么要用混合Vue.mixin的方式来写呢?主要原因是使用代码在前,Router实例在后创建,安装逻辑需要使用这个实例。2.创建router-view和router-linkVueRouter.install=function(_Vue){//省略挂载代码内容...//2.注册两个组件router-view,router-link//router-view是一个ContainerVue.component('router-view',{render(h){//获取路由表//这里是一个vue组件,this.$router是可以访问的const{routeMap,current}=this.$routerconstcomponent=routeMap[current]?routeMap[current].component:nullreturnh(component)}})//xxxVue.component('router-link',{props:{to:{type:String,default:''},},//h为createElementrender(h){//参数1标签类型//参数2传入各种属性和事件returnh('a',{attrs:{href:'#'+this.to}},this.$slots.default)//也可以使用jsx//return{this.$slots.default}}})}Vue.component是vue创建组件的一种方式。render中的h函数其实就是createElement方法。Vue也支持jsx语法,但是在vue中不推荐这样使用。routeMap和current实际上是在VueRouter类初始化的时候在下面定义的。3.处理路由表classVueRouter{constructor(options){//缓存路径和路由映射关系this.routeMap={}this.$options.routes.forEach(route=>{this.routeMap[route.path]=route});}}写成key,value方式使用方便。4、监听url变化为什么我们的路由变化时页面会刷新?首先,我们必须能够监控路由变化。在hash模式下,hashchange可以监听路由变化,然后我们需要在变化后响应通知页面变化。classVueRouter{constructor(options){//创建current以保存当前url//为了使用current重新渲染组件//它应该是响应式的constinitial=window.location.hash.slice(1)||'/'Vue.util.defineReactive(this,'current',initial)//监听hashchange时间window.addEventListener('hashchange',this.onHashChange.bind(this))window.addEventListener('load',this.onHashChange.bind(this))}onHashChange(){//修改当前url,hash格式#/xxxthis.current=window.location.hash.slice(1)}}Vue.util.defineReactive定义了一个responsive属性,一旦current发生变化,router-view组件将重新渲染。5.引用变化的使用是一样的,只是这里介绍的vue-router是你刚才创建的文件夹。从'vue'导入Vue从'./vue-router'导入VueRouter从'./Home.vue'导入主页Vue.use(VueRouter)constroutes=[{path:'/',name:'Home',component:Home},{path:'/about',name:'About',component:()=>import(/*webpackChunkName:"about"*/'./About.vue')}]constrouter=newVueRouter({routes})exportdefaultrouter至此,vue-router的基本功能已经实现。希望大家看完这篇文章后,能够对vue-router是如何监听页面变化,如何更新页面有一个深刻的理解。