《Vuejs设计与实现》8.6 区分vnode的类型

252 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第31天,点击查看活动详情

在上文中,我们推定当渲染一个null或者空元素的时候,表示卸载,除了这两种情况,则会把vnode执行patch操作.patch翻译一下叫补丁,作为动词就是打补丁。其实,我觉得所谓补丁就是对新旧vnode进行对比,对比的时候,我们需要区分vnode的类型。

比如说,我们模板里有一个简单的v-if

<template>
    <p v-if="a">213</p>
    <input v-else />
</template>

假设这时候,a变化了,由true变成了false,我们就大概有这样一个函数调用

const oldNode = {type:'p',children:'123'}
const newNode = {type:'input'}
patch(oldNode,newNode,container)

在这种情况下,再次对比二者的不同是没有必要的,这是两种完全不同的Node,我们需要做的就是卸载旧的,渲染新的。 因此,我们在patch中就需要先判断类型

const patch = (oldNode,newNode,container)=>{
    if(oldNode.type!==newNode.type){
        unmount(oldNode)
        oldNode = null
    }
    /* 省略其他逻辑 */
}

卸载完成之后,相当于旧Node已经不存在了,我们将他置为null,这样才能不影响后续逻辑。书中讲到这里就算完了,但是实际上,虚拟node很少只是一个简单标签,大部分时候,我们对比的都应该是组件.

比如,ElINput指的是elementUI里input组件,如果我们直接通过===去对比,有可能是相等的,但是这不一定是同一个组件,我可能v-model变化了,或者别的props变化了,但是都是指向的同一个组件的对象。

const oldNode = {type:ElINput}
const newNode = {type:ElINput}

因此,我觉得这里区分vnode的类型,应该是一个递归的对比方法,而不是简单的对比type的值。或者说,当type是字符串的时候,可以进行简单比较,当type类型是对象的时候,需要进行递归比较,对比全部propsattrs 这时候,我就觉得我把属性扁平化会方便很多了,减少很多递归。