调试updateChildren

Vue

# 没有key的情况

# 准备模板

<!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>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 设置断点

  1. 找到core/vdom/patch.js中updateChildren定义的位置,点击按钮看到断点执行到这里

image

  1. 这个时候oldCh是button节点,我们要看的是li节点,所以按F8到执行的是li的时候

image

  1. 这个时候找到新老节点对比的断点,让代码执行到这个断点处

image

# 开始调试

  1. 当前oldStartVnode的tag是li

image

  1. 按F10运行到两个开始子节点比较sameVnode的时候,按F11进入函数

当前的key都是undefined,tag都是li标签

image

  1. 按F10结束之后,F11进入patchVnode

image

  1. 一路F10到比较这个子节点中的文本节点

image

  1. 再一次F11进入updateChildren,并跳转到之前打断点的位置,这个时候可以看到两个的text都是a

image

  1. 按F10,进入判断,执行到patchVnode的地方

image

  1. 按F11进入,判断其text是相同的,所以这里不更新DOM

image

所以第一个节点就处理完成了,下面来第二个li节点的处理过程,这时候两个节点虽然tag一样,但是文本节点不同,一个是b一个是x,下面重复上面的操作从1直到5的地方,可以看到b和x进行比较,两者不同

image

  1. 此时会执行nodeOps.setTextContent(elm, vnode.text),会更新DOM,这个函数执行完毕,可以看到DOM上面已经发生了变化.

image

  1. 第二个节点处理完成,第三个节点,重复上面的操作,可以看到一个节点是c一个节点是b,还是1到5,可以看到c和b进行比较,两者不同,那么要更新DOM

image

执行完毕这句可以看到视图发生了改变

image

  1. 第四个节点也是一样,d和c比较更新DOM

image

执行完毕之后可以看到视图发生了改变

image

  1. 第四个节点,按F10可以看到老节点已经遍历完成

image

image

  1. 这个时候新节点还没有遍历完成,所以执行addVnodes添加节点,按F11进入addVnodes

image

  1. 执行完毕之后可以看到视图中增加了最后一个元素

image

# 总结

这个调试的过程完成了,在没有设置key的情况下,更新了3次DOM,插入了一次DOM,总共执行了4次DOM操作

# 有key的情况

# 模板html

在原来的基础上添加key属性

<div id="app">
  <button @click="handler">按钮</button>
  <ul>
    <li v-for="value in arr" :key="value">{{ value }}</li>
  </ul>
</div>
1
2
3
4
5
6

# 断点

断点和上面不设置key的一样

# 调试

点击按钮进入调试,重复没有key的时候的1-5步骤,因为a没有发生变化所以没有更新DOM,

  1. 第二个节点li的情况就发生了变化,现在执行到sameVnode的情况,当前的key不相同

image

image

  1. 这两个节点不是同一个vnode所以继续向下执行,下面比较新旧数组的结束节点,都是key是d的,tag是li的节点,是相同节点

image

  1. 按F11进入patchVnode,重复没有key时的3-5步骤,此时文本节点都是d所以不会更新dom

image

  1. 执行完毕之后视图没有发生任何变化,结束节点的索引都向前移动,进入下一次比较,先重复1,还是先比较b和x,不是相同节点向下执行,比较新旧结束节点,现在的结束节点的key是c,tag是li,是相同节点

image

image

  1. 所以这里,会进入patchVnode判断两个节点的内容,发现文本节点也相同,所以这里不会更新dom,结束节点的索引都往前移动

image

  1. 接下来还是先重复1,先比较b和x,不是相同节点往下执行,比较新旧结束节点,现在的结束节点的key是b,tag是li,是相同节点

image

image

  1. 所以这里也会判断两个节点的内容,文本节点也相同不会更新dom,结束节点的索引都往前移动

image

  1. 进入下一次循环的时候,可以看到老节点的开始索引比老节点的结束索引大了,说明老节点已经循环完毕了,同样此时新节点的循环也结束完毕了.

image

  1. 这个时候去判断老节点数组已经遍历完成,但是新节点中还有,所以将新节点的剩下的元素都创建节点添加到DOM树上

image

  1. 执行完成之后可以看到新元素添加到了DOM树上

image

# 总结

这里面,只更创建过一次DOM,这里可以看出设置key比不设置key的操作更少。

更新时间: 2022-01-13 21:13