vue的matcher_vue-router工作原理概述和问题分析

工作原理简要流程图

hashchange

-->

match route

-->

set vm._route

-->

render()

-->

render matched component

问题

1. 为什么url变更时,router-view组件就能渲染出在routes中定义的与当前path匹配的组件?

root vue实例上定义了一个响应式属性Vue.util.defineReactive(this, '_route', this._router.history.current)

url变更时,会匹配到最新的route,并且会设置 this._routerRoot._route, 触发setter

router-view组件的render函数中有使用到 parent.$route, 也就是间接的触发了this._routerRoot._route的getter。即进行了依赖搜集。

则this._routerRoot._route的setter触发时即会触发router-view的渲染watcher, 再次渲染, 并且此时拿到的路由组件也是最新的。

本质上利用了vue的响应式属性,在route属性变更和router-view视图渲染之间建立关系。

route变更 => render重新渲染

2. router-view render中使用到parent.$route为什么就会被this._routerRoot._route收集watcher

在挂载router-view组件时,会生成一个watcher, router-view的render函数中又触发了_route的getter方法,那么此watcher就被收集到_route的Dep中了。

在_route的setter触发时,自然执行了这个watcher, 组件重新render。

在 vue的仓库中vue/src/core/instance/lifecycle.js中mountComponent方法中,能看到挂载组件时是会生成一个watcher的:

export function mountComponent(

vm: Component,

el: ?Element,

hydrating?: boolean

) {

...

let updateComponent

updateComponent = () => {

vm._update(vm._render(), hydrating)

}

new Watcher(vm, updateComponent, noop, {

before() {

...

}

})

...

return vm

}

3. this.$router, this.$route是怎么挂载每个vue组件上的?

Object.defineProperty(Vue.prototype, '$router', {

get () { return this._routerRoot._router }

})

Object.defineProperty(Vue.prototype, '$route', {

get () { return this._routerRoot._route }

})

4.替换routes的写法(这样写为什么有用)

// 替换现有router的routes

router.matcher = new VueRouter({

routes: newRoutes

}).matcher

router.matcher是比较核心的一个属性。对外提供两个方法match(负责route匹配), addRoutes(动态添加路由)。

具体原因:在做路径切换transitionTo方法中,首先就会使用const route = this.router.match(location, this.current)来匹配route, 其实内部会使用matcher来做匹配。修改了matcher即新的routes生效。

match (

raw: RawLocation,

current?: Route,

redirectedFrom?: Location

): Route {

// 这里使用matcher的match方法来做匹配

return this.matcher.match(raw, current, redirectedFrom)

}

对router.matcher属性做修改,即新的routes就会替换老的routes, 其实就是replaceRoutes()的含义(但是官方没有提供这个API)。

export type Matcher = {

match: (raw: RawLocation, current?: Route, redirectedFrom?: Location) => Route;

addRoutes: (routes: Array) => void;

};

5. router-view是什么

组件是一个functional 组件,渲染路径匹配到的视图组件。 渲染的组件还可以内嵌自己的 ,根据嵌套路径,渲染嵌套组件。

主要流程

初始化

实例化Router, options作为属性,根据mode生成HTML5History实例,或HashHistory实例

数据劫持,this.router.route =》 this.history.current

数据劫持,this.history.current.route变化时,自动执行render。

立即执行一次路由跳转(渲染路由组件)

路由监听

HashHistory监听hashChange事件,HTML5History监听popstate事件

路由变化处理

两种方式触发路由变化

a标签href方法(url先变化,会触发两个history监听的hashChange或popstate事件,然后进入路由变化处理)

调用router的push, replace, go方法(先进入路由变化处理,然后修改url)

路由变化具体处理过程

history.transitionTo(根据path匹配到相应的route, 然后调度执行hooks, 然后更新this.current属性,触发视图更新)

history.confirmTransition(调度执行上一个route和下一个route的相关生命周期hooks)

router的辅助API

push(先进行路由变化处理,在更新url,使用history.pushState)

replace() 和push处理方式一致, 只是更新url使用history.replaceState

go 使用history.go方法

参考链接

https://zhuanlan.zhihu.com/p/... 这篇文章讲的也比较详细,最好的是提供了自己造的vue-router的简易版轮子,更方便大家理解,这个轮子很好。 【推荐阅读轮子这一部分】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值