# 模版编译

# 模版渲染过程

vue template complier,将模版编译为render函数(利用with函数),执行render函数生成vnode。 模版不是html 有指令 插值 js表达式 能实现判断 循环

模版通过compile 生成AST,AST通过render编译生成 VNode代码片段。 基于VNode我们执行patch和diff。

const compiler = require('vue-template-compiler');
//template模版
const template = `
<p id="container">
   <span v-if="flag === 'a' ">A</span>
   <span v-else>B</span>
</p>
`;

//模版编译生成AST
const res = compiler.compile(template);
console.log(res);
{
  ast: {
    type: 1,
    tag: 'p',
    attrsList: [ [Object] ],
    attrsMap: { id: 'container' },
    rawAttrsMap: {},
    parent: undefined,
    children: [ [Object] ],
    plain: false,
    attrs: [ [Object] ],
    static: false,
    staticRoot: false
  },
  render: `with(this){return _c('p',{attrs:{"id":"container"}},[(flag === 'a' )?_c('span',[_v("A")]):_c('span',[_v("B")])])}`,
  staticRenderFns: [],
  errors: [],
  tips: []
}

//AST通过render生成VNode

console.log(res.render())
//生成的with函数return一个 _c函数,就是createElement。执行函数体返回VNode。
//with(this){return _c('p',{attrs:{"id":"container"}},[(flag === 'a' )?_c('span',[_v("A")]):_c('span',[_v("B")])])}

我们通过 vue-template-compiler,可以将template转换成with函数的VNode。但是在实际开发环境中,我们通过webpack打包经过vue-loader处理之后,生成的dist文件就已经是一段段的编译好的with函数了。

# 直接写render函数

vue中可以通过直接写render函数,取代template。 React使用jsx语法糖,直接使用render,没有template。

Vue.component('Hello',{
  render:function (createElement){
   return createElement(
     'h'+this.level,
    [
      createElement('a',{
        attr:{
          name:'head',
          href:'#'
        }
      },'this is link')
    ]
   )
  }
})

# 渲染过程

  • 1 解析template为render函数(或在开发环境已经完成,vue-loader。正常单页webpack打包通过vue-loader,就已经变成了render函数)
  • 2 触发响应式,observe的过程。
  • 3 执行render函数,生成vnode,patch(elem,vnode)

# 更新过程

  • 修改data,触发setter
  • 重新执行render函数,生成 newVnode
  • patch(VNode,newVVode)