Vue源码学习(二) 数据驱动原理
本文主要讲的是Vue数据驱动的源码分析,即我们定义在data中的变量是如何渲染到页面上的。
我们以带compiler版本的vue源码进行分析,来解释页面渲染过程中是如何将数据渲染到页面上的。
Mount函数
1 | //entry-runtime-with-compiler.js |
这段代码首先是判断是否由render函数,如果没有判断是否有template,再根据template生成render函数,总之,vue的mount阶段只认render函数。
我们再来看一下最后调用的mount函数
1 | // platform/web/runtime/index.js |
这一步很简单,找到挂载点el,然后执行mountComponent函数。
mountComponent
1 | // core/instance/lifecycle.js |
在这一步中会创建渲染Watcher,那我们再看一下Watcher是什么?
Watcher
1 | export default class Watcher { |
我们可以看到在构造函数中会调用get方法,而该方法会首先pushTarget,也就是上篇博客响应式原理中讲的那样,将this赋值给一个全局的变量Dep.target,然后调用传入的updateComponent函数,该函数会调用render函数,渲染过程中用到的data[keyUsed]都会触发其getter,从而把Dep.target加入到data[keyUesd]的subs中。
_render
我们在回过头来看一下updateComponent函数中调用的_render函数
它是被initRender函数挂载到了Vue的原型上的
1 | Vue.prototype._render = function (): VNode { |
_renderProxy的值从何而来
这段代码是_init函数中定义的,也就是说prod环境下这个proxy就是自己
1 | if (process.env.NODE_ENV !== 'production') { |
那为什么非prod下需要设置一层代理,这层代理又是做什么的呢?
这个问题就不展示源码了,简单来说这层代理的作用就是一些错误的提示,所以在prod下就不需要这层代理了。
$createElement
1 | vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true) |
1 | // wrapper function for providing a more flexible interface |
_update
上面通过_render函数可以获得一个vnode,拿到这个vnode之后我们可以继续执行传入watcher中的updateComponent函数,也就是
vm._update(vm._render(), hydrating)
1 | // core/instance/lifecycle.js |
_patch
1 | //platforms/web/runtime/index.js |
1 | //platforms/web/runtime/patch.js |
这个createPatchFunction非常复杂,定义了大量的辅助函数,最终返回的是patch函数,这里只展示分析patch函数,其他辅助函数简单提一下它的用途。
1 | return function patch (oldVnode, vnode, hydrating, removeOnly) { |