Appearance
调试updateChildren
没有key的情况
准备模板
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Vue.js 01 component example</title>
</head>
<body>
<div id="app">
<button @click="handler">按钮</button>
<ul>
<li v-for="value in arr">{{ value }}</li>
</ul>
</div>
<script src="../../dist/vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
arr: ['a','b','c','d']
},
methods: {
handler () {
this.arr.splice(1, 0, 'x')
}
}
})
</script>
</body>
</html>
设置断点
- 找到core/vdom/patch.js中updateChildren定义的位置,点击按钮看到断点执行到这里
- 这个时候oldCh是button节点,我们要看的是li节点,所以按F8到执行的是li的时候
- 这个时候找到新老节点对比的断点,让代码执行到这个断点处
开始调试
- 当前oldStartVnode的tag是li
- 按F10运行到两个开始子节点比较sameVnode的时候,按F11进入函数
当前的key都是undefined,tag都是li标签
- 按F10结束之后,F11进入patchVnode
- 一路F10到比较这个子节点中的文本节点
- 再一次F11进入updateChildren,并跳转到之前打断点的位置,这个时候可以看到两个的text都是a
- 按F10,进入判断,执行到patchVnode的地方
- 按F11进入,判断其text是相同的,所以这里不更新DOM
所以第一个节点就处理完成了,下面来第二个li节点的处理过程,这时候两个节点虽然tag一样,但是文本节点不同,一个是b一个是x,下面重复上面的操作从1直到5的地方,可以看到b和x进行比较,两者不同
- 此时会执行
nodeOps.setTextContent(elm, vnode.text)
,会更新DOM,这个函数执行完毕,可以看到DOM上面已经发生了变化.
- 第二个节点处理完成,第三个节点,重复上面的操作,可以看到一个节点是c一个节点是b,还是1到5,可以看到c和b进行比较,两者不同,那么要更新DOM
执行完毕这句可以看到视图发生了改变
- 第四个节点也是一样,d和c比较更新DOM
执行完毕之后可以看到视图发生了改变
- 第四个节点,按F10可以看到老节点已经遍历完成
- 这个时候新节点还没有遍历完成,所以执行addVnodes添加节点,按F11进入addVnodes
- 执行完毕之后可以看到视图中增加了最后一个元素
总结
这个调试的过程完成了,在没有设置key的情况下,更新了3次DOM,插入了一次DOM,总共执行了4次DOM操作
有key的情况
模板html
在原来的基础上添加key属性
html
<div id="app">
<button @click="handler">按钮</button>
<ul>
<li v-for="value in arr" :key="value">{{ value }}</li>
</ul>
</div>
断点
断点和上面不设置key的一样
调试
点击按钮进入调试,重复没有key的时候的1-5步骤,因为a没有发生变化所以没有更新DOM,
- 第二个节点li的情况就发生了变化,现在执行到sameVnode的情况,当前的key不相同
- 这两个节点不是同一个vnode所以继续向下执行,下面比较新旧数组的结束节点,都是key是d的,tag是li的节点,是相同节点
- 按F11进入patchVnode,重复没有key时的3-5步骤,此时文本节点都是d所以不会更新dom
- 执行完毕之后视图没有发生任何变化,结束节点的索引都向前移动,进入下一次比较,先重复1,还是先比较b和x,不是相同节点向下执行,比较新旧结束节点,现在的结束节点的key是c,tag是li,是相同节点
- 所以这里,会进入patchVnode判断两个节点的内容,发现文本节点也相同,所以这里不会更新dom,结束节点的索引都往前移动
- 接下来还是先重复1,先比较b和x,不是相同节点往下执行,比较新旧结束节点,现在的结束节点的key是b,tag是li,是相同节点
- 所以这里也会判断两个节点的内容,文本节点也相同不会更新dom,结束节点的索引都往前移动
- 进入下一次循环的时候,可以看到老节点的开始索引比老节点的结束索引大了,说明老节点已经循环完毕了,同样此时新节点的循环也结束完毕了.
- 这个时候去判断老节点数组已经遍历完成,但是新节点中还有,所以将新节点的剩下的元素都创建节点添加到DOM树上
- 执行完成之后可以看到新元素添加到了DOM树上
总结
这里面,只更创建过一次DOM,这里可以看出设置key比不设置key的操作更少。