3-2-26-Vue.js 源码阅读-模板编译-概述

Vue 模板编译-概述

  • 模板编译的作用?

    • Vue2.0 使用 vnode 描述视图以及各种交互,用户自己编写 vnode 比较复杂
    • 模板编译可以让用户只需要编写类似 HTML 的代码 - Vue.js 模板,通过编译器将模板转换为返回 vnode 的 render 函数
    • .vue 文件会被 webpack 在构建的过程中转换为 render 函数

运行时编译的前提必须是使用完整版的 Vue,它会再运行时把模板转换成 render 函数。因为多了编译器的代码,使得 Vue 的体积变大,运行的速度也会相应的变慢。Vue-cli 创建的项目默认使用的运行时版本的 Vue。

模板编译的结果

在 src/platforms/web/entry-runtime-with-compiler.js 中定义了 Vue.$mount, 在这个方法中首先会判断是否传入了 render 函数,如果没有传入 render 函数,判断是否传入了 template ,如果没有传入 template 就会把 el 的 outerHTML 作为 template 。

获取到 template 之后会调用 compileToFunctions 这个方法将 template 转换成 render 函数。

一个编译生成的 render 函数

(ƒunction anonymous() {
  with (this) {
    return _c(
      'div', 
      { attrs: { "id": "app" } }, 
      [
        _m(0), 
        _v(" "), 
        _c('p', [_v(_s(msg))]), 
        _v(" "), 
        _c('comp', { on: { "myclick": handler } })
      ], 
      1
    ); 
  }
});

可以看到在 render 函数中就是调用了 Vue 中挂载的下划线开头的方法来生成 vnode

  • _c()
    • src/core/instance/render.js
  • _m()/_v()/_s()
    • src/core/instance/render-helpers/index.js
// 对编译生成的 render 进行渲染的方法
vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)

_m()/_v()/_s() 这几个成员是在 Vue 的实例成员初始化的 renderMixin 中调用 installRenderHelpers 方法给实例挂载的用于生成 vnode 的实例方法。

export function renderMixin (Vue: Class<Component>) {
  // install runtime convenience helpers
  installRenderHelpers(Vue.prototype)
}

installRenderHelpers 方法如下

export function installRenderHelpers (target: any) {
  target._o = markOnce
  target._n = toNumber
  target._s = toString // 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 // 创建文本 vnode 节点
  target._e = createEmptyVNode
  target._u = resolveScopedSlots
  target._g = bindObjectListeners
  target._d = bindDynamicKeys
  target._p = prependModifier
}
  • _v
export function createTextVNode (val: string | number) {
  return new VNode(undefined, undefined, undefined, String(val))
}
  • _s
/**
 * Convert a value to a string that is actually rendered.
 */
export function toString (val: any): string {
  return val == null
    ? ''
    : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)
      ? JSON.stringify(val, null, 2)
      : String(val)
}
  • render 函数分析

render 函数的核心是调用 _c 这个方法也就是 _createElement() 生成并返回 vnode。

上述 render 函数对应的 template

<div id="app">
  <h1>Vue<span>模板编译过程</span></h1>
  <p>{{ msg }}</p>
  <comp @myclick="handler"></comp>
</div>

_c 中的参数

  • “div” 是标签名
  • { attrs: { “id”: “app” } }, 是标签属性
  • 下一个数组是 children
  • boolean 是处理 children 的方法,如果传1,就是将 children 拍平,如果 children 是多维数组转换成一维数组。

children 的处理

  • _m(0) 处理静态内容
  • _v(" ") 创建一个空白vnode文本节点
  • _c('p', [_v(_s(msg))]) 创建 p 标签
  • _c('comp', { on: { "myclick": handler } }) 创建组件

可以使用 Vue Template Explorer 这个工具来分析 template 对应的 render 函数

  • https://template-explorer.vuejs.org/
  • https://vue-next-template-explorer.netlify.app/
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值