VueJS 的编译阶段到挂载节点
栏目: JavaScript · 发布时间: 6年前
内容简介:为了实现响应式模式,Vue用render函数来生成vnode,并使用diff算法对比新旧vnode,最后更新到真实DOM上。由于是在编译阶段而不是在监听阶段,所以vnode没有对比的对象,直接通过vnode生成真实DOM。Vnode是Vdom上的一个节点,是对真实DOM的抽象,在Vue中,我们可以通过对比新旧Vnode和Vdom来得到需要更新真实DOM的操作,并通过Vue框架来执行这些操作。于是我们可以把更多的精力投放到业务逻辑上。
为了实现响应式模式,Vue用render函数来生成vnode,并使用diff算法对比新旧vnode,最后更新到真实DOM上。
由于是在编译阶段而不是在监听阶段,所以vnode没有对比的对象,直接通过vnode生成真实DOM。
Vnode是Vdom上的一个节点,是对真实DOM的抽象,在Vue中,我们可以通过对比新旧Vnode和Vdom来得到需要更新真实DOM的操作,并通过Vue框架来执行这些操作。于是我们可以把更多的精力投放到业务逻辑上。
编译阶段
该阶段会解析template,把template转化为render函数会经过三个过程:
- parse,将 template 模板中进行字符串解析,得到指令、class、style等数据,形成 AST
- optimize,这个阶段用于优化 patch阶段 ,标记节点的 static 属性是否是静态的
- generate,将 AST 转化成 render funtion 字符串,最终得到 render 的字符串以及 staticRenderFns 字符串
如果使用vue-cli工具的话,借助webpack可以在打包过程中把template转化为render函数和staticRenderFns函数
render 的字符串与render 函数的关系
render函数内部包含render字符串:
function render(vm) { with(vm) { eval(render_string) } } 复制代码
挂载节点
Vue实例化的最后一步就是挂载节点。该阶段会分为两步:
- 通过render函数获得vnode
- 通过传入vnode给patch函数生成真实DOM并挂载到页面上
render函数被执行时机
那么render函数在什么时候会被再次执行呢?
在解释VueJS 响应式原理的时候有提到过,Render-Watcher实例的getter就是执行render函数的:
updateComponent = () => { vm._update(vm._render(), hydrating) } new Watcher(vm, updateComponent, noop, { before () { if (vm._isMounted) { callHook(vm, 'beforeUpdate') } } }, true /* isRenderWatcher */) 复制代码
所以,render函数会被执行的时机有:
- Vue初始化的时候,会执行一次
- 当template(模板)中需要观察的数据对象更新值的时候,也会触发render函数(render-watcher)执行
render函数的关键是 _createElement
,负责返回VNode,它会根据标签名是否存在已注册的组件中,返回普通VNode或是组件VNode:
export function _createElement ( context: Component, tag?: string | Class<Component> | Function | Object, data?: VNodeData, children?: any, normalizationType?: number ): VNode | Array<VNode> { // ....... let vnode, ns if (typeof tag === 'string') { let Ctor ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag) if (config.isReservedTag(tag)) { // platform built-in elements vnode = new VNode( config.parsePlatformTagName(tag), data, children, undefined, undefined, context ) } else if (isDef(Ctor = resolveAsset(context.$options, 'components', tag))) { // component vnode = createComponent(Ctor, data, context, children, tag) } else { // unknown or unlisted namespaced elements // check at runtime because it may get assigned a namespace when its // parent normalizes children vnode = new VNode( tag, data, children, undefined, undefined, context ) } } else { // direct component options / constructor vnode = createComponent(tag, data, context, children) } if (Array.isArray(vnode)) { return vnode } else if (isDef(vnode)) { if (isDef(ns)) applyNS(vnode, ns) if (isDef(data)) registerDeepBindings(data) return vnode } else { return createEmptyVNode() } } 复制代码
patch函数执行时机
和render函数的一样,因为patch函数就在 vm._update(vm._render(), hydrating)
中的_update里。
- 在Vue初始化的时候,会生成真实DOM并挂载到document上
- 当template(模板)中需要观察的数据对象更新值的时候,会对比新旧vnode,并返回新vnode对应的真实DOM
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) { const vm: Component = this const prevEl = vm.$el const prevVnode = vm._vnode const prevActiveInstance = activeInstance activeInstance = vm vm._vnode = vnode // Vue.prototype.__patch__ is injected in entry points // based on the rendering backend used. if (!prevVnode) { // 初始化渲染 vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */) } else { // 更新渲染 vm.$el = vm.__patch__(prevVnode, vnode) } activeInstance = prevActiveInstance // update __vue__ reference if (prevEl) { prevEl.__vue__ = null } if (vm.$el) { vm.$el.__vue__ = vm } // if parent is an HOC, update its $el as well if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) { vm.$parent.$el = vm.$el } // updated hook is called by the scheduler to ensure that children are // updated in a parent's updated hook. } 复制代码
更新的patch函数的核心是diff算法,类似git的diff指令,大致逻辑如下:
通过对比新旧vnode,找到更新真实DOM需要的所有操作,比如新增、删除、替换节点的操作。然后通过Vue框架来执行这些更新DOM的操作,最后返回更新的DOM。
参考
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Kubernetes集群跨节点挂载CephFS
- Kubernetes集群跨节点挂载CephFS
- 文件系统挂载
- vue 源码学习 - 实例挂载
- linux 磁盘管理与文件挂载
- [Recovery]自动挂载system分区
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Mastering Regular Expressions, Second Edition
Jeffrey E F Friedl / O'Reilly Media / 2002-07-15 / USD 39.95
Regular expressions are an extremely powerful tool for manipulating text and data. They have spread like wildfire in recent years, now offered as standard features in Perl, Java, VB.NET and C# (and an......一起来看看 《Mastering Regular Expressions, Second Edition》 这本书的介绍吧!