前言
上篇文章中分析了Moon中虚拟DOM的整个逻辑处理,它是Moon整个功能实现的核心,本篇的要说明的slot以及指令的处理都是在上篇文章分析的逻辑过程中,只是上篇文章没有突出说明具体的处理,本篇就是具体的说明Moon是如何处理slot以及指令的。
具体分析
还是通过实例来开始分析整个过程,具体实例代码如下:
<div id="app">
<p m-if="true">{{getToday}}</p>
<mn-test>
<p>{{today}}</p>
<p slot="second">hello world</p>
</mn-test>
</div>
<script src="./moon.js"></script>
<script>
debugger
Moon.component('mn-test', {
template: `<div>
<slot></slot>
<slot name="second"></slot>
</div>`
});
new Moon({
el: '#app',
data: {
today: Date.now()
},
computed: {
getToday: {
get() {
var now = new Date(this.get('today'));
return now.toLocaleString();
}
}
}
});
</script>
上面的实例中涉及到了slot以及指令m-if。
- 首先整个的过程还是如同虚拟DOM中的处理
- 需要说明的是m-if在tokens中也是作为标签属性的存在,slot也是作为token中也是作为标签属性的存在
- 在返回render的处理中,lex以及parse中的处理没有什么不同,主要的不同是在于generate中部分即渲染时的具体内容的替换。
generate中关于slot以及指令的处理
generate函数的逻辑处理如下:
在具体分析了generateEL函数的处理逻辑,关于slot以及指令的核心逻辑如下:
var compiledCode = "";
// 是否存在插槽slot
if (vnode.type === "slot") {
parentVNode.meta.shouldRender = true;
parentVNode.deep = true;
var slotNameAttr = vnode.props.attrs.name;
compiledCode = 'instance.$slots[\'' + (slotNameAttr && slotNameAttr.value || "default") + '\']';
} else {
// 创建函数体
compiledCode = createCall(vnode, parentVNode);
}
// 虚拟DOM是否存在指令相关的对象
if (vnode.specialDirectivesAfter !== undefined) {
for (var specialDirectiveAfterInfo in vnode.specialDirectivesAfter) {
var specialDirectiveAfter = vnode.specialDirectivesAfter[specialDirectiveAfterInfo];
compiledCode = specialDirectives[specialDirectiveAfter.name].afterGenerate(specialDirectiveAfter.value, specialDirectiveAfter.meta, compiledCode, vnode);
}
}
上面的代码就是generateEL中关于slot以及指令的处理。
上面就说过在lex中生成tokens,上面实例中m-if以及slot都是作为对应标签的属性的,所以就会在createCall中,slot的处理从上面可以直接看出,而对于指令的处理,就要具体分析了。
指令相关
if (vnode.specialDirectivesAfter !== undefined) {
具体代码
}
需要判断虚拟DOM是否存在specialDirectivesAfter对象,通过具体的分析,该对象的添加是在createCall中对于属性的处理,相关处理代码如下:
var attrInfo = attrs[attr];
var specialDirective = null;
// 是否是Moon实例内置的指令
if ((specialDirective = specialDirectives[attrName]) !== undefined) {
if (specialDirective.afterGenerate !== undefined) {
// 添加specialDirectivesAfter对象
if (vnode.specialDirectivesAfter === undefined) {
vnode.specialDirectivesAfter = {};
}
// 指令相关赋值
vnode.specialDirectivesAfter[attr] = attrInfo;
}
if (specialDirective.duringPropGenerate !== undefined) {
generatedObject += specialDirective.duringPropGenerate(attrInfo.value, attrInfo.meta, vnode);
}
vnode.meta.shouldRender = true;
delete attrs[attr];
}
从上面的处理逻辑看出,Moon指令的具有特定的结构,下面就看看m-if的构成:
specialDirectives[Moon.config.prefix + "if"] = {
afterGenerate: function (value, meta, code, vnode) {
return '(' + compileTemplate(value, delimiters, escapedDelimiters, false) + ') ? ' + code + ' : h("#text", ' + generateMeta(defaultMetadata()) + ', "")';
}
};
具体看看compileTemplate的处理逻辑:
compileTemplate的处理结果是:
(true) ? h("p", {attrs: {}}, {"shouldRender": true, "eventListeners": {}}, [h("#text", {"shouldRender": true, "eventListeners": {}}, "" + instance.get("getToday") + "")]) : h("#text", {"shouldRender": false, "eventListeners": {}}, "")
compileTemplate函数还是根据不用的指令处理成不同的render的部分函数体。
对于其他指令,具体的处理我会详细注释,Moon内置的指令都是对象,对象拥有方法beforeGenerate、duringPropGenerate、afterGenerate,这些方法afterGenerate是在generate函数中处理,beforeGenerate和duringPropGenerate是在generateProps中处理。