vue 源码分析 step_2-渲染函数如何生成 Vnode并最终生成真实 DOM?

我们知道经过编译器生成的代码字符串,最终要通过渲染函数 createElement 生成 Vnode,也知道编译生成的代码字符串会有_f,_m,_v,_c...的特征


export function createComponent (
  Ctor: Class<Component> | Function | Object | void,
  data: ?VNodeData,
  context: Component,
  children: ?Array<VNode>,
  tag?: string
): VNode | Array<VNode> | void {
......
  const vnode = new VNode(
    `vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
    data, undefined, undefined, undefined, context,
    { Ctor, propsData, listeners, tag, children },
    asyncFactory
  )
......

  return vnode
}

这个就是最终产出的 vnode 了。

为什么代码字符串中的_c,_v就能创建不同的 vnode? 

在src/core/instance/render-helpers/index.js 中

export function installRenderHelpers (target: any) {
  target._o = markOnce
  target._n = toNumber
  target._s = toString
  target._l = renderList
  target._t = renderSlot
  target._q = looseEqual
  target._i = looseIndexOf
  target._m = renderStatic
  target._f = resolveFilter
  target._k = checkKeyCodes
  target._b = bindObjectProps
  target._v = createTextVNode
  target._e = createEmptyVNode
  target._u = resolveScopedSlots
  target._g = bindObjectListeners
  target._d = bindDynamicKeys
  target._p = prependModifier
}

这样,就将我们的代码字符串与响应创建Vnode 的方法对应起来了。


我们要经过 diff, patch 等过程,最后得到更新之后的 DOM。这是其中 patch过程中,我们已经知道该如何修改 DOM的一处代码,此处的修改是调用nodeOps.nextSibling方法

canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))

其中 nodeOps.insertBefore 就是原生的方法,文件为platforms/web/runtime/node-ops.js:

...
export function createTextNode (text: string): Text {
  return document.createTextNode(text)
}

export function createComment (text: string): Comment {
  return document.createComment(text)
}

export function insertBefore (parentNode: Node, newNode: Node, referenceNode: Node) {
  parentNode.insertBefore(newNode, referenceNode)
}
...

到此为止,我们完成了初始化,一次简单 diff 之后的 DOM 生成工作

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页