路由注册
改一下例子
main.js
1 | // The Vue build version to load with the `import` command |
App.vue
1 | <template> |
从Vue.use(VueRouter)
开始吧
1 | function initUse (Vue) { |
这个方法接受一个 plugin
参数,并且有一个存储所有注册过的 plugin
的数组,它会判断plugin
是否有install
方法,有就执行,然后把plugin
添加到installedPlugins
数组
走进install
方法
1 | var _Vue; |
1)installed
判断是否安装过
2)Vue.mixin
把beforeCreate
和destroyed
钩子函数注册到组件上
3)把Vue.prototype
上的$router
和$route
变成响应式对象
4)Vue.component
定义了两个组件
VueRouter
看下创建router
实例的时候做了什么
1 | const router = new VueRouter({ |
这个是VueRouter
构造函数
1 | var VueRouter = function VueRouter (options) { |
1)this.options
保留了传入的options
参数
2)this.matcher
表示路由匹配器
进入createMatcher
方法
1 | function createMatcher ( |
首先走进createRouteMap
方法,这里是创建一个路由映射表
1 | function createRouteMap ( |
走进去addRouteRecord
方法
1 |
|
最后得到的就是 pathList
、pathMap
和 nameMap
。其中 pathList
是为了记录路由配置中的所有 path
,而 pathMap
和 nameMap
都是为了通过 path
和 name
能快速查到对应的 RouteRecord
。
3)this.fallback
表示根据传入的配置参数,并且浏览器是否支持,初始化不同history
实例
这个例子中的history
实例
之后返回VueRouter
的实例router
在new Vue
的时候,走进init
之后,触发beforeCreate
生命周期钩子(在上面做mergeOptions
操作(参数合并)的时候,为vm.$options
添加(或合并)的钩子函数)
进入调用钩子函数
1 | beforeCreate: function beforeCreate () { |
进入this._router.init(this)
1 | VueRouter.prototype.init = function init (app /* Vue component instance */) { |
先进入transitionTo
方法
1 | History.prototype.transitionTo = function transitionTo ( |
1)根据location
与this.current
找到匹配到目标的路径
2)进入confirmTransition
方法做真正的切换,最后会执行传入的onComplete
回调,其实最后调用的是history.setupListeners
1 | HashHistory.prototype.setupListeners = function setupListeners () { |
这里会根据浏览器支持和选择,监听popstate
或者haschange
事件,设置回调
init
之后调用Vue中定义的defineReactive
对_route
进行劫持,这个劫持之前有说过,其实是执行的依赖收集的过程,执行_route
的get
就会对当前的组件进行依赖收集,如果对_route
进行重新赋值触发setter就会使收集的组件重新渲染。(完成依赖收集在mount
阶段,生成RouterView
的vnode
的时候收集依赖)
点击router-link
组件试一下,执行了router.push(location,noop)
这个location
参数在这里,组件render
的时候获得的
走进push
方法
1 | VueRouter.prototype.push = function push (location, onComplete, onAbort) { |
进入this.history.push
方法
1 | HashHistory.prototype.push = function push (location, onComplete, onAbort) { |
进入transitionTo
方法
1 | History.prototype.transitionTo = function transitionTo ( |
获取到跳转的路由对象,进入confirmTransition
方法,最后触发传入的回调函数
1 | function () { |
进入updateRoute
方法
1 | History.prototype.updateRoute = function updateRoute (route) { |
进入this.cb
回调,遍历this.$1.apps
,修改_route
属性,触发setter
,之后触发视图更新
1 | history.listen(function (route) { |
这个this.$1.apps
是在init
的时候往里面push
值
最后调用回调函数
走进去pushHash
1 | function pushHash (path) { |
走进pushState
1 | function pushState (url, replace) { |
router-link与a标签的区别
router-link组件有自己的render方法,在这里添加了on的属性,之后生成DOM结构的时候就会为a标签添加
a标签点击的时候,进去handler方法
guardEvent判断是否event上有preventDefault,有就调用,阻止默认行为
总结
hash路由,根据情况使用的不同
1 | var supportsPushState = inBrowser && (function () { |
supportsPushState为true的时候:
use方法,调用install方法,为所有组件添加beforeCreate和destroyed钩子,还有定义了RouterView和RouterLink组件,并且让\$router和$route变成响应式
创建router实例,根据不同的支持实例化不同的history,还有个match方法匹配地址。
new Vue 进入beforeCreate钩子调用,调用transitionTo,根据location匹配出route,调用comfirmTransiton,之后添加监听事件popstate,渲染视图(routerlink渲染)
点击routerlink生成的a标签,触发点击事件,被阻止冒泡,之后调用router.push(location, noop); 进入history.push,又进入了transitionTo,调用dep.notify,之后调用 history.pushState({ key: _key }, ‘’, url); (比如”http://localhost:8080/#/foo")之后更新搜索栏地址。
更新视图
supportsPushState为false的时候:
use方法,调用install方法,为所有组件添加beforeCreate和destroyed钩子,还有定义了RouterView和RouterLink组件,并且让\$router和$route变成响应式
创建router实例,根据不同的支持实例化不同的history,还有个match方法匹配地址。
new Vue 进入beforeCreate钩子调用,调用transitionTo,根据location匹配出route,调用comfirmTransiton,之后添加监听事件hashchange,渲染视图(routerlink渲染)。
- 点击routerlink生成的a标签,触发点击事件,被阻止冒泡,之后调用router.push(location, noop); 进入history.push,又进入了transitionTo,调用dep.notify,之后调用pushHash(route.fullPath),因为supportsPushState为false所以执行的是window.location.hash = path(比如path是/foo) ,之后更新搜索栏地址。也触发了hashchange事件
- 更新视图