淺析Vue原始碼(六)—— $mount中template的編譯--generate

DIVI發表於2018-10-05

上兩文章

淺析Vue原始碼(四)—— $mount中template的編譯--parse

淺析Vue原始碼(五)—— $mount中template的編譯--optimize

parse,optimize函式的功能,這裡,我們主要介紹generate。

generate 函式主要功能就是根據 AST 結構拼接生成 render function 的字串。

export function generate (
  ast: ASTElement | void,
  options: CompilerOptions
): CodegenResult {
  const state = new CodegenState(options)
  const code = ast ? genElement(ast, state) : '_c("div")'
  return {
  // 最外層包一個 with(this) 之後返回
    render: `with(this){return ${code}}`,
    // 這個陣列中的函式與 VDOM 中的 diff 演算法優化相關
    // 我們會在編譯階段給後面不會發生變化的 VNode 節點打上 staticRoot 為 true 的標
    // 那些被標記為 staticRoot 節點的 VNode 就會單獨生成 staticRenderFns
    staticRenderFns: state.staticRenderFns
  }
}
複製程式碼

其中 genElement 函式是什麼呢?--是會根據 AST 的屬性呼叫不同的方法生成字串返回。也就是拼接字串了:

export function genElement (el: ASTElement, state: CodegenState): string {
  if (el.staticRoot && !el.staticProcessed) {
    return genStatic(el, state)
  } else if (el.once && !el.onceProcessed) {
    return genOnce(el, state)
  } else if (el.for && !el.forProcessed) {
    return genFor(el, state)
  } else if (el.if && !el.ifProcessed) {
    return genIf(el, state)
  } else if (el.tag === 'template' && !el.slotTarget) {
    return genChildren(el, state) || 'void 0'
  } else if (el.tag === 'slot') {
    return genSlot(el, state)
  } else {
    // component or element
    let code
    if (el.component) {
      code = genComponent(el.component, el, state)
    } else {
      const data = el.plain ? undefined : genData(el, state)

      const children = el.inlineTemplate ? null : genChildren(el, state, true)
      code = `_c('${el.tag}'${
        data ? `,${data}` : '' // data
      }${
        children ? `,${children}` : '' // children
      })`
    }
    // module transforms
    for (let i = 0; i < state.transforms.length; i++) {
      code = state.transforms[i](el, code)
    }
    return code
  }
}
複製程式碼

以上就是 compile 函式中三個核心步驟的介紹,compile 之後我們得到了 render function 的字串形式,後面通過 new Function 得到真正的渲染函式。DOM 初始化過程最後一步是根據渲染函式生成 Vnode,根據此 Vnode 生成真實 DOM,插入 DOM 樹中,並將該 Vnode 記錄為 preVnode。

要是喜歡就給我一個star,github

感謝muwoo提供的思路。

相關文章