携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情
前文中主要讨论了挂载,还有挂载时如何设置元素,这一节将要讨论如何卸载元素。卸载主要发生在更新阶段,对应于vue的生命周期updated,也是我们之前的还未完全实现的patch函数。
我们之前实现了渲染一个虚拟DOM,可以使用renderer.render(vnode,container),然后我们会在patch中对比,如果只是vnode的内容,属性变化了,我们可以直接重新赋值,但如果vnode不存在了,我们就需要出发卸载操作,比如
renderer.render(null,container)
在之前实现的patch函数里,当元素卸载时,简单粗暴的调用了container.innerHTML = ''。诚然,这样是最简单,最快速的清除DOM的方法,但这样是不行的,书中写了3点原因:
- container中可能有多个DOM,对应着就是多个虚拟DOM,这样操作会直接清空其他vnode,也就是相邻组件。
- 其他元素中可能有自定义指令,应当执行指令中卸载元素的回调函数
innerHTML不会解绑事件
解决的办法很简单,我们需要把虚拟Node与真实NODE联系起来,我们可以这样操作
const el = createElement(vnode.type);vnode.el=el,把渲染出来的真是元素放到vnode的结构里,这样我们卸载的时候,可以根据这个el属性执行卸载。
因此,我们可以封装出来一个unmount函数,来执行卸载操作。
function unmount(vnode){
const p = vnode.el.parentNode
if(p){
//执行其他操作
p.removeChild(vnode.el)
}
}
之所以封装起来,不仅仅是因为少写一次removeChild,原因在前文也说过,卸载元素的时候还要考虑是否有自定义指令,自定义指令中是否有卸载的相关操作,可以在这里执行。
是否有事件或者自定义事件,我们也可以在这里解绑。甚至还要触发beforeUnmount或者beforeDestroy这些vue的声明周期。
封装起来,我们也可以把这些操作都集中起来,方便管理和执行