# 文档初探(四): 列表渲染

# 使用v-for

# 对 Object 使用v-for

上面是对数组使用v-for, 这里对 Object 使用v-for.

# key的作用

key的作用是为了在 diff 算法执行时更快的找到对应的节点,提高 diff 速度. 如果在列表渲染里不用key, 那就是不好的实践? 也不一定, 得分情况来判断. Vue 使用in-place patch来处理改动列表数据的渲染方式: 它会直接改变 DOM 节点的属性达到效果. 比如有

它会生成五个div节点:

[
  "<div>1</div>", // id: A
  "<div>2</div>", // id:  B
  "<div>3</div>", // id:  C
  "<div>4</div>", // id:  D
  "<div>5</div>" // id:  E
];
1
2
3
4
5
6
7

当我们改动数据源: vm.dataList = [5,4,3,2,1]

接着 Vue 生成新的 Virtual DOM, 和旧的 Virtual DOM 进行比较, 发现它们的节点都没有变化, 于是触发默认方法(in-place patch), 把各自divinnerText替换为新的dataList. 如果给每个节点加一个id. 那么它们的id是不变的:

[
  "<div>5</div>", // id: A
  "<div>4</div>", // id:  B
  "<div>3</div>", // id:  C
  "<div>2</div>", // id:  D
  "<div>1</div>" // id:  E
];
1
2
3
4
5
6
7

默认方法是有局限性的, Vue 文档里这样说:

This default mode is efficient, but only suitable when your list render output does not rely on child component state or temporary DOM state (e.g. form input values).

为了解决它, 我们使用key, 给每个列表的 item 加上一个key属性, 相当于给每个 item 一个标识, 给上面的例子加上一个key属性后, 它更新的方式就会发生变化:

[
  "<div>5</div>", // id: E
  "<div>4</div>", // id:  D
  "<div>3</div>", // id:  C
  "<div>2</div>", // id:  B
  "<div>1</div>" // id:  A
];
1
2
3
4
5
6
7

Vue 直接交换了 DOM 的位置, 如果我们对数据有增删, 那么也会相应地触发 DOM 的增删节点的操作. 同时这样的操作方式也会带来性能开销比原来大的问题.

WARNING

用数组的 index 作为 key 与不用 key 是一样的, 因为在数组里删除一个数, 那么其后面的一位数会立马占位被删掉的数, 后面的也是如此, 被删数的后面的所有 item 的 index 都会发生变化.会造成 bug.

# 检测数组的改变

Vue 会检测data里数组的变化, 一些方法会触发视图的更新,. 这些方法其实就是 JS 里会改变原数组的方法吗, 如push(), splice(), sort(), reverse()等. 所以, 对于那些不改变原数组的方法(filter(), concat(), slice())我们可以使用赋值的方式来触发视图的更新.

WARNING

由于 JS 的限制, Vue 不能检测到下面两种情况的数组改变:

  1. 直接设置数组的某项的值: vm.items[indexOfItem] = newValue
  2. 修改数组的长度: vm.items.length = newLength

TIP

为了解决上述的问题, 这里提供解决方法:

针对第一种情况:

  1. Vue.set(vm.items, indexOfItem, newValue)
  2. vm.items.splice(indexOfItem, 1, newValue)

针对第二种情况:

vm.items.splice(newLength)

# 检测对象改变

# 新增对象属性

  1. Vue.set(object, propertyName, value)

  2. vm.$set(object, propertyName, value)

  3. vm.object = Object.assign({}, vm.object, {
      // options
    });
    
    1
    2
    3

# v-if & v-show

  • v-show: expensive initial load, cheap toggling
  • v-if: cheap initial load, expensive toggling