生命周期
name | avatars | company |
---|---|---|
constructor | 构造函数 | new的时候 |
install | 初始化安装,这可以拿到用户传进的data进行处理 | 实例化 |
installed | 安装完成,HTML已经插入页面之后执行 | 实例化 |
uninstall | 卸载组件。执行remove方法会触发该事件 | 销毁时 |
beforeUpdate | 更新前 | 存在期 |
afterUpdate | 更新后 | 存在期 |
示意图
以上是官网的,看着让人还是挺明白的。但是我还是喜欢用我的理解解说一把。
生命周期指一个对象的生老病死。具体来说是继承Omi.Component类的子类的实例的生命周期。
1. 当我们 new 子类的时候, 子类的实例会得到Omi.Component类的所以属性和方法。
2. 当我们使用Omi.render方法时,其实调用的是Component类上的_render方法,在这个方法前后会分别调用install和installed方法,就如上图的左边部分。
3. 实例的存在期呢,我们经常会调用updade方法更新dom节点,那在这个update方法之前会分别调用beforeUpdate和afterUpdate,就如上图的右边部分。
4. 实例销毁期,就是就是调用实例的remove方法,期间也会调用update方法(那么必然会调用beforeUpdate,afterUpdate方法),之后呢会调用uninstall方法。就如上图的右下角部分。
老规矩:先上demo代码, 然后提出问题, 之后解答问题, 最后源码说明。
class Timer extends Omi.Component { constructor(data) { super(data); } install() { console.log('install'); this.data = { secondsElapsed: 0 }; } tick() { this.data.secondsElapsed ++; this.update(); } installed() { console.log('installed'); this.interval = setInterval(() => { this.tick(); }, 1000); } uninstall() { console.log('uninstall'); clearInterval(this.interval); } style() { return ` .num { color: red; } `; } beforeUpdate() { console.log('beforeUpdata'); } render() { console.log('render'); return ` <div> Seconds Elapsed: <span class="num"> {{secondsElapsed}} </span> </div> `; } afterUpdate() { console.log('afterUpdate'); } }; var time = new Timer(); Omi.render(time, '#app'); setTimeout(() => { time.remove(); console.log('已卸载!'); }, 10000);
demo的疑问和疑问的说明:
疑问1:
Omi.render(time, '#app');的時候是不是就执行了install 和 installed 方法 啊?
答:是的,一般可以在install方法中给实例设置数据, installed方法中update设置好的数据。怎么实现的如下:
上图中的2那个方法主要用来遍历实例是否还有孩子,有的话就遍历孩子,调用孩子的installed方法。如果孩子还有孩子就递归
_childrenInstalled(root){ // 实例 root.children.forEach((child) => { // 遍历实例的每一个孩子 this._childrenInstalled(child); // 递归(看看自己的孩子还有没有孩子children) child.installed(); // 调用孩子实例installed方法 }); }
3那边的代码就执行installed方法。
这就是使用omi.render方法时要走的过程。
疑问2:
更新节点使用update方法,这个update到底做了什么?
答:
这个的要细细看来了,如下
1 这里调用了beforeUpdate方法。
2 这里上面有解释,看代码,如下:
_childrenBeforeUpdate(root) { // 实例的孩子render方法前的回调 root.children.forEach((child)=>{ child.beforeUpdate(); // 跟新孩子的beforeUpdate方法回调 this._childrenBeforeUpdate(child); // 孩子的孩子 }); }
3 这里就是重新生成html css 事件转换,但是并不是无脑innerHTML,而是通过morphdom(this.node, this.HTML);来跟新节点的,这个morphdom不是虚拟dom,只是局部跟新dom节点,感兴趣的可以看看他的源码。
4 这里看看代码
_childrenAfterUpdate(root){ root.children.forEach((child)=>{ this._childrenAfterUpdate(child); // 孩子的孩子的afterUpdate方法 child.afterUpdate(); // 孩子的afterUpdate方法 }); }
5 那里就是调用自身的afterUpdate()方法,至此结束了。
疑问3:
实例的remove方法帮我们做了啥啊?
答:帮我们update了节点,只不过把节点改成了input节点影藏节点,然后调用了uninstall方法。如下:
咋们直接进入1方法去看看
1 和 3 就是所谓生命周期的方法调用,我们进入2看看去,
其实要看的代码只是画圈的那个,我们进1看看,怎么帮我们生成一个影藏节点的,代码如下
之后就把以前的this.node节点直接换成这个创建好的节点。然后回到remove方法中的uninstall方法,就完了。
ps:
了解omi.Component实例的生命周期,当和子组件搭配时,可以很清楚了自己干了啥。