template 转化成 render 的流程
1.先判断是否存在el
// 模板渲染流程if (vm.$options.el) {vm.$mount(vm.$options.el);}
先判断是否改在el,有就会直接执行$mount(),即
vm.$mount => Vue.prototype.$mount = function(){}
el 不能是 body 和 html 这两个元素
/* istanbul ignore if */if (el === document.body || el === document.documentElement) {warn("Do not mount Vue to <html> or <body> - mount""to normal elements instead.");return this}
2.是否存在render()
当确定了 el 以后,紧接着看的不是 template,先看是否存在 render 函数,如果存在render(),则会执行:
return mount.call(this, el, hydrating) // 此处的mount与$mount不一样
3.是否存在template
不存在render之后,就会立刻进入以下判断,获取template
if (template) {if (typeof template === 'string') {if (template.charAt(0) === '#') {template = idToTemplate(template);/* istanbul ignore if */if (!template) {warn(("Template element not found or is empty: " + (options.template)),this);}}} else if (template.nodeType) {template = template.innerHTML;} else {{warn('invalid template option:' + template, this);}return this}}
获取到 template 内容以后:
调用 compileToFunctions(template); --》返回一个对象 refref.renderoptions.render = ref.render
通过 compileToFunctions 把字符串模板编译一个对象,该对象有一个 render 方法,这个方法就会作为组件的 render 方法
总的来说:
render => template => 会根据 template 的类型去处理模板的内容来源 => el 存在,el.outerHTML
compileToFunctions
模板解析
// 不是连续的代码,从源码中抽出来var compiled = compile(template, options);var compiled = baseCompile(template.trim(), finalOptions);var createCompiler = createCompilerCreator(function baseCompile (template,options) {// 生成抽象语法树var ast = parse(template.trim(), options);if (options.optimize !== false) {optimize(ast, options);}// 利用generate将ast生成所需要的代码var code = generate(ast, options);return {ast: ast,render: code.render,staticRenderFns: code.staticRenderFns}});
parse 把 html => ast 对象
ast 抽象语法树 => 生成各种代码 => (js => html => java => php)
var ast = parse(template.trim(), options);
generate 函数把 ast 生成我们需要的代码
var code = generate(ast, options);
// code实际上生成一段字符串with(this){return \_c('div',{attrs:{"id":"app2"}},[\_c('h1',[_v("开课吧")])])}
将code作为参数传入new Function()
function createFunction (code, errors) {try {return new Function(code)} catch (err) {errors.push({ err: err, code: code });return noop}}
createElemnet 函数
- 一个直接调用,render 函数里面的 createElement
- 一个通过 template 生成// 内部使用的 createElement 别名vm._c = function (a, b, c, d) { return createElement(vm, a, b, c, d, false); };// 对外提供的createElementvm.$createElement = function (a, b, c, d) { return createElement(vm, a, b, c, d, true); };
流程
( html -> AST -> )渲染函数 -> vNode -> DOM
