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); --》返回一个对象 ref
ref.render
options.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); };
// 对外提供的createElement
vm.$createElement = function (a, b, c, d) { return createElement(vm, a, b, c, d, true); };
流程
( html -> AST -> )渲染函数 -> vNode -> DOM