template 转化成 render 的流程

一切都从一个Vue实例开始,new Vue()

1.先判断是否存在el

  1. // 模板渲染流程
  2. if (vm.$options.el) {
  3. vm.$mount(vm.$options.el);
  4. }

先判断是否改在el,有就会直接执行$mount(),即
vm.$mount => Vue.prototype.$mount = function(){}

el 不能是 body 和 html 这两个元素

  1. /* istanbul ignore if */
  2. if (el === document.body || el === document.documentElement) {
  3. warn(
  4. "Do not mount Vue to <html> or <body> - mount"
  5. "to normal elements instead."
  6. );
  7. return this
  8. }

2.是否存在render()

当确定了 el 以后,紧接着看的不是 template,先看是否存在 render 函数,如果存在render(),则会执行:

  1. return mount.call(this, el, hydrating) // 此处的mount与$mount不一样

3.是否存在template

不存在render之后,就会立刻进入以下判断,获取template

  1. if (template) {
  2. if (typeof template === 'string') {
  3. if (template.charAt(0) === '#') {
  4. template = idToTemplate(template);
  5. /* istanbul ignore if */
  6. if (!template) {
  7. warn(
  8. ("Template element not found or is empty: " + (options.template)),
  9. this
  10. );
  11. }
  12. }
  13. } else if (template.nodeType) {
  14. template = template.innerHTML;
  15. } else {
  16. {
  17. warn('invalid template option:' + template, this);
  18. }
  19. return this
  20. }
  21. }

获取到 template 内容以后:

  1. 调用 compileToFunctions(template); --》返回一个对象 ref
  2. ref.render
  3. options.render = ref.render

通过 compileToFunctions 把字符串模板编译一个对象,该对象有一个 render 方法,这个方法就会作为组件的 render 方法
总的来说:

render => template => 会根据 template 的类型去处理模板的内容来源 => el 存在,el.outerHTML

compileToFunctions

模板解析

  1. // 不是连续的代码,从源码中抽出来
  2. var compiled = compile(template, options);
  3. var compiled = baseCompile(template.trim(), finalOptions);
  4. var createCompiler = createCompilerCreator(function baseCompile (
  5. template,
  6. options
  7. ) {
  8. // 生成抽象语法树
  9. var ast = parse(template.trim(), options);
  10. if (options.optimize !== false) {
  11. optimize(ast, options);
  12. }
  13. // 利用generate将ast生成所需要的代码
  14. var code = generate(ast, options);
  15. return {
  16. ast: ast,
  17. render: code.render,
  18. staticRenderFns: code.staticRenderFns
  19. }
  20. });

parse 把 html => ast 对象
ast 抽象语法树 => 生成各种代码 => (js => html => java => php)
var ast = parse(template.trim(), options);
generate 函数把 ast 生成我们需要的代码
var code = generate(ast, options);

  1. // code实际上生成一段字符串
  2. with(this){return \_c('div',{attrs:{"id":"app2"}},[\_c('h1',[_v("开课吧")])])}

将code作为参数传入new Function()

  1. function createFunction (code, errors) {
  2. try {
  3. return new Function(code)
  4. } catch (err) {
  5. errors.push({ err: err, code: code });
  6. return noop
  7. }
  8. }

createElemnet 函数

  • 一个直接调用,render 函数里面的 createElement
    - 一个通过 template 生成
    1. // 内部使用的 createElement 别名
    2. vm._c = function (a, b, c, d) { return createElement(vm, a, b, c, d, false); };
    3. // 对外提供的createElement
    4. vm.$createElement = function (a, b, c, d) { return createElement(vm, a, b, c, d, true); };

流程

( html -> AST -> )渲染函数 -> vNode -> DOM