介绍
riot.mount
是riot加载模板的内容并结合传入的数据渲染出dom并更新到页面上的入口函数。
用法
最常用的用法:
selector
(字符串)样式选择器,id、类名、标签选择器都可以tagName
(字符串)需要被加载的模板文件的名字,注意这里并不是文件的名字,而是模板内容中最顶层的tag名字,如:
opts
(对象)传入的数据,类似react的props,[]表示可选
demo
先写一个最简单的demo(注意这里使用了necoo-loader分析):
todo.tag 内容:
<todo h="1">
<div class="{cls}">{name}: {desc}{console.log('hello world')} {myFunc()}</div>
// logic comes here
let self = this;
self.desc = '真帅';
self.name = 'HongRunhui'
self.myFunc = function () {
console.log('你好');
};
self.cls = 'content';
function beforeBeforeMount() {
window.necooPush(arguments);
}
beforeBeforeMount();
self.on('before-mount', function myBeforeMount() {
window.necooPush(arguments);
});
self.on('mount', function myMount() {
window.necooPush(arguments);
});
self.on('update', function myUpdate() {
window.necooPush(arguments);
});
self.on('updated', function myUpdated() {
window.necooPush(arguments);
});
</todo>
执行轨迹图:
现象分析:
我用红色箭头标出了比较重要的几个步骤,黄色箭头则是我们上面todo.tag中埋下的钩子函数,可以看到beforeBeforeMount
是早于myBeforeMount
函数的,另外myMount
是晚于myBeforeMount
。所以在riot中的生命周期函数是这样的:
before-before-mount
(实际上没有这个,这里我是用来表示直接写在script标签里的函数)before-mount
mount
以及发现在mount
的过程中并没有触发self.on('update')
和 self.on('updated')
;
代码分析:
为了方便大家理解,我直接把上述标出的一系列比较重要的函数给列出来简单解释一下:
mount
入口函数?
选择要被加载到的父元素pushTagsTo
一个包含递归的函数,将?中选择出来的节点进行循环加载tag标签mount$1
开始真正加载某一个具体的模板tagcreateTag
根据__IMPL_缓存下来的模板信息新建一个tag实例componentMount
tag实例创建好之后,开始将tag实例更新到dom中parseAttributes
解析?
选择出来的父元素上的属性,并保存到tag实例上walAttributes
解析__IMPL_模板中已经解析好的attrs属性(如todo标签上的属性),并保存到tag实例上parseAttributes
解析上一个步骤获取到的属性,如果有表达式,就丢到一个表达式数组里保存起来,如果没有,就同步到?
选择出来的父元素上。updateOpts
更新传入的optsmixin
将window.__global_mixin
上的方法绑定到tag实例上。beforeBeforeMount
执行script里的js,这个时候我们写在todo.tag中这么写的数据let self = this; this.myLists = [1,2,3]
中的myLists就会绑定到tag实例上。myBeforeMount
如果有监听这个,这个对应的函数就会被触发parseExpressions
通过遍历模板的HTML节点,将模板中的包含{title}
这类的表达式给解析出来,存放到一个表达式数组变量expressions
中componentUpdate
解析上面的expressions数组,使用new Function
来获取tag实例上的变量值,生成最终包含数据的字符串模板,插入到dom中,最终将这个dom插入到?
选出来的父元素中。
以上就是是大致的流程。
{xxx} => Hello
这种模板语法最终是怎么替换成有数据的的呢?
举个栗子:
<div class="{cls}">{name}: {desc}{console.log('hello world')} {myFunc()}</div>
其中div内的内容都会被处理成这种函数并执行,来读取tag实例上的变量。
(function anonymous(E) {
return [
function _anonymous_15(v) {
window.necooPush(arguments);
v = (("name"in this ? this : window).name);
return v || v === 0 ? v : ""
}.call(this)
,
": ",
function _anonymous_15(v) {
window.necooPush(arguments);
v = (("desc"in this ? this : window).desc);
return v || v === 0 ? v : ""
}.call(this),
function _anonymous_15(v) {
window.necooPush(arguments);
try {
v = ("console"in this ? this : window).console.log('hello world')
} catch (e) {
E(e, this)
}
;return v || v === 0 ? v : ""
}.call(this),
" ",
function _anonymous_15(v) {
window.necooPush(arguments);
try {
v = ("myFunc"in this ? this : window).myFunc()
} catch (e) {
E(e, this)
}
;return v || v === 0 ? v : ""
}.call(this)
].join("");
})