阅读 64

Vue 模板语法——列表渲染(4)

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

1. 虚拟 DOM

上一小节中提到,如果上面 <div> 元素中放的不是文本,而是其它多个元素这一情形,这时它们实际上就形成了一个 VNode Tree,也就是虚拟 DOM 了:

image-20210725193823299.png

也就是说,虚拟 DOM 的每个节点都是一个 VNode,虚拟 DOM 就是由一个个的 VNode 组成的。

需要注意的是,虚拟 DOM 和 真实 DOM 在正常情况下(有组件时,虽然组件也会生成 VNode,但组件本身不会被渲染)不是一一对应的。

2. 插入 F 的案例

我们先来看一个案例:点击按钮,在字母列表中间插入字母 F

<body> 中的代码如下:

<div id="app"></div>

<template id="my-app">
  <ul>
    <li v-for="item in letters">{{ item }}</li>
  </ul>
  <button @click="insertF">插入字母 F</button>
</template>

<script src="./js/vue.js"></script>
<script>
  const App = {
    data() {
      return {
        letters: ['A', 'B', 'C', 'D']
      }
    },
    methods: {
      insertF() {
        this.letters.splice(2, 0, 'F');
      }
    },
    template: '#my-app'
  };

  Vue.createApp(App).mount('#app');
</script>
复制代码

在插入字母 F 时,数组发生了变化,页面因此会进行更新,我们可以确定的是,这次更新不会对 <ul><button> 元素进行更新,需要更新的是 <li> 元素列表,即应该插入一个 <li> 元素。

那么我们来思考这样一个问题:如何插入这个 <li> 元素,效率才是最高的呢?

  • 方案 1:不管三七二十一先把原来的这几个 <li> 元素对应的 DOM 全删了,然后根据最新的 <li> 元素列表先生成新的 VNodes,之后再重新渲染出真实 DOM。显然,这样做效率很低。
  • 方案 2:依次对比新旧 VNodes,当和旧 VNode 不一样时才做相应变化(修改/新增/删除),之后只重新渲染有变化的 VNodes。在本案例中,就是对比新旧 VNodes 时,原先的 AB 元素都不变动,原先的 C 改为 F,原先的 D 改为 C,最后再新增一个 VNode D。这种做法相比于上面的做法性能高些,但仍不够好,因为看起来可以重复利用的 CD 还是被做了修改,所以性能也不是很高。
  • 方案 3:可能的拥有最高性能的方案是这样的:对比新旧 VNodesABCD 都不要动,直接在中间插入 F。如何实现呢?这就涉及到 diff 算法了。
文章分类
前端
文章标签