-
Notifications
You must be signed in to change notification settings - Fork 473
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
vue-router源码分析-整体流程 #9
Comments
流程图看不见 |
看不太懂0.0 |
消失的分析图。。 |
有需要看 才看的懂 勉强看很累 |
请问下,你这个图是用什么软件做的。 |
正在研究动态路由添加,看了这篇分析理解的更清楚了 👍 |
路由配置在new VueRouter()前提供的,有没有可以创建实例后再动态给路由配置添加 |
@NehoDeveloper vue-router 2.2.0+ 的版本提供了 router.addRoutes(routes) 方法可以动态添加配置,可以参考文档 https://router.vuejs.org/zh-cn/api/router-instance.html |
使用vue-router 两个页面使用同一组件不同参数来控制,(非keep-alive模式下)打开这俩个页面不是根据组件实例出俩个对象而是一直在操作一个对象,俩个页面的数据没有隔离,而是相互影响。(俩页面切换可以通过监听路由来做相应的处理,可是这样的话用户在一个页面操作的一半的数据,去看另一个页面,再回来的时候 数据就没有了,我想如果vue-router渲染同一组件不同页面时都是实例出不同的对象来渲染就解决了),以上的分析是我看了上面的分析得出的,如果有错请告知,如果没有错,请问解决此问题您有什么方案。谢了 @dolymood |
这些业务逻辑代码里用到的一些泛型我看都是在types文件夹里,但是这些文件并没有被引用,那是如何使用这些接口的,求大神指教 |
请教下,在入口文件已经有了Vue.use(VueRouter)这,为什么还要在index文件要重复写这样的代码? |
@zjxzjx54 入口文件的Vue.use(VueRouter)是使用者自己添加的 |
呜呜,看不懂。我还会回来的 |
😂
…On Thu, Jan 28, 2021 at 2:14 PM xiaozhu5566 ***@***.***> wrote:
呜呜,看不懂。我还会回来的
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#9 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AHKBRWLHI5TZPPIMMAOH7XLS4D6FFANCNFSM4CYGBEFA>
.
|
你这个你自己都已经给出了解决方案了,组件化就是为了复用,data返回函数就是为了不操作同一个对象。你导入一次组件,页面里写两个不就好了,根据参数不同展示两个其中的一个。你要非要用一个组件来展示,那就做数据缓存,把数据存到vuex里,切换的时候根据参数去取就行了,不过这样就有点本末倒置了。 |
你好,有个地方不太懂,请问可以帮忙解答一下嘛? |
在现在单页应用这么火爆的年代,路由已经成为了我们开发应用必不可少的利器;而纵观各大框架,都会有对应的强大路由支持。Vue.js 因其性能、通用、易用、体积、学习成本低等特点已经成为了广大前端们的新宠,而其对应的路由 vue-router 也是设计的简单好用,功能强大。本文就从源码来分析下 Vue.js 官方路由 vue-router 的整体流程。
首先来张整体的图:
先对整体有个大概的印象,下边就以官方仓库下
examples/basic
基础例子来一点点具体分析整个流程。目录结构
先来看看整体的目录结构:
和流程相关的主要需要关注点的就是
components
、history
目录以及create-matcher.js
、create-route-map.js
、index.js
、install.js
。下面就从 basic 应用入口开始来分析 vue-router 的整个流程。入口
首先看应用入口的代码部分:
作为插件
上边代码中关键的第 1 步,利用 Vue.js 提供的插件机制
.use(plugin)
来安装VueRouter
,而这个插件机制则会调用该plugin
对象的install
方法(当然如果该plugin
没有该方法的话会把plugin
自身作为函数来调用);下边来看下 vue-router 这个插件具体的实现部分。VueRouter
对象是在src/index.js
中暴露出来的,这个对象有一个静态的install
方法:可以看到这是一个 Vue.js 插件的经典写法,给插件对象增加
install
方法用来安装插件具体逻辑,同时在最后判断下如果是在浏览器环境且存在window.Vue
的话就会自动使用插件。install
在这里是一个单独的模块,继续来看同级下的src/install.js
的主要逻辑:这里就会有一些疑问了?
Vue.prototype
定义$router
、$route
属性就可以把他们注入到所有组件中吗?beforeCreate mixin
这个在后边创建 Vue 实例的时候再细说。实例化
VueRouter
在入口文件中,首先要实例化一个
VueRouter
,然后将其传入 Vue 实例的options
中。现在继续来看在src/index.js
中暴露出来的VueRouter
类:里边包含了重要的一步:创建
match
匹配函数。match
匹配函数匹配函数是由
src/create-matcher.js
中的createMatcher
创建的:具体逻辑后续再具体分析,现在只需要理解为根据传入的
routes
配置生成对应的路由 map,然后直接返回了match
匹配函数。继续来看
src/create-route-map.js
中的createRouteMap
函数:可以看出主要做的事情就是根据用户路由配置对象生成普通的根据
path
来对应的路由记录以及根据name
来对应的路由记录的 map,方便后续匹配对应。实例化 History
这也是很重要的一步,所有的
History
类都是在src/history/
目录下,现在呢不需要关心具体的每种History
的具体实现上差异,只需要知道他们都是继承自src/history/base.js
中的History
类的:实例化完了
VueRouter
,下边就该看看Vue
实例了。实例化
Vue
实例化很简单:
options
中传入了router
,以及模板;还记得上边没具体分析的beforeCreate mixin
吗,此时创建一个 Vue 实例,对应的beforeCreate
钩子就会被调用:具体来说,首先判断实例化时
options
是否包含router
,如果包含也就意味着是一个带有路由配置的实例被创建了,此时才有必要继续初始化路由相关逻辑。然后给当前实例赋值_router
,这样在访问原型上的$router
的时候就可以得到router
了。下边来看里边两个关键:
router.init
和 定义响应式的_route
对象。router.init
然后来看
router
的init
方法就干了哪些事情,依旧是在src/index.js
中:可以看到初始化主要就是给
app
赋值,针对于HTML5History
和HashHistory
特殊处理,因为在这两种模式下才有可能存在进入时候的不是默认页,需要根据当前浏览器地址栏里的path
或者hash
来激活对应的路由,此时就是通过调用transitionTo
来达到目的;而且此时还有个注意点是针对于HashHistory
有特殊处理,为什么不直接在初始化HashHistory
的时候监听hashchange
事件呢?这个是为了修复vuejs/vue-router#725这个 bug 而这样做的,简要来说就是说如果在beforeEnter
这样的钩子函数中是异步的话,beforeEnter
钩子就会被触发两次,原因是因为在初始化的时候如果此时的hash
值不是以/
开头的话就会补上#/
,这个过程会触发hashchange
事件,所以会再走一次生命周期钩子,也就意味着会再次调用beforeEnter
钩子函数。来看看这个具体的
transitionTo
方法的大概逻辑,在src/history/base.js
中:可以看到整个过程就是执行约定的各种钩子以及处理异步组件问题,这里有一些具体函数具体细节被忽略掉了(后续会具体分析)但是不影响具体理解这个流程。但是需要注意一个概念:路由记录,每一个路由
route
对象都对应有一个matched
属性,它对应的就是路由记录,他的具体含义在调用match()
中有处理;通过之前的分析可以知道这个match
是在src/create-matcher.js
中的:路由记录在分析
match
匹配函数那里以及分析过了,这里还需要了解下创建路由对象的createRoute
,存在于src/util/route.js
中:回到之前看的
init
,最后调用了history.listen
方法:listen
方法很简单就是设置下当前历史对象的cb
的值, 在之前分析transitionTo
的时候已经知道在history
更新完毕的时候调用下这个cb
。然后看这里设置的这个函数的作用就是更新下当前应用实例的_route
的值,更新这个有什么用呢?请看下段落的分析。defineReactive 定义 _route
继续回到
beforeCreate
钩子函数中,在最后通过Vue
的工具方法给当前应用实例定义了一个响应式的_route
属性,值就是获取的this._router.history.current
,也就是当前history
实例的当前活动路由对象。给应用实例定义了这么一个响应式的属性值也就意味着如果该属性值发生了变化,就会触发更新机制,继而调用应用实例的render
重新渲染。还记得上一段结尾留下的疑问,也就是history
每次更新成功后都会去更新应用实例的_route
的值,也就意味着一旦history
发生改变就会触发更新机制调用应用实例的render
方法进行重新渲染。router-link 和 router-view 组件
回到实例化应用实例的地方:
可以看到这个实例的
template
中包含了两个自定义组件:router-link
和router-view
。router-view 组件
router-view
组件比较简单,所以这里就先来分析它,他是在源码的src/components/view.js
中定义的:可以看到逻辑还是比较简单的,拿到匹配的组件进行渲染就可以了。
router-link 组件
再来看看导航链接组件,他在源码的
src/components/link.js
中定义的:可以看出
router-link
组件就是在其点击的时候根据设置的to
的值去调用router
的push
或者replace
来更新路由的,同时呢,会检查自身是否和当前路由匹配(严格匹配和包含匹配)来决定自身的activeClass
是否添加。小结
整个流程的代码到这里已经分析的差不多了,再来回顾下:
相信整体看完后和最开始的时候看到这张图的感觉是不一样的,且对于 vue-router 的整体的流程了解的比较清楚了。当然由于篇幅有限,这里还有很多细节的地方没有细细分析,后续会根据模块来进行具体的分析。
The text was updated successfully, but these errors were encountered: