Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

为什么使用v-for时必须添加唯一的key? #10

Open
lvwxx opened this issue Jul 22, 2019 · 0 comments
Open

为什么使用v-for时必须添加唯一的key? #10

lvwxx opened this issue Jul 22, 2019 · 0 comments
Labels
question Further information is requested

Comments

@lvwxx
Copy link
Owner

lvwxx commented Jul 22, 2019

vue视图更新机制

  1. 状态变更,重新渲染一个完整的Virtual DOM对象。
  2. 新旧Virtual Dom对比,记录两棵树的差异。
  3. 对差异的地方进行真正的DOM操作。
  4. 新的Virtual Dom对象替换旧的Virtual Dom。

Virtual Dom对比算法(Diff 算法)

  1. 基于两个基本假设:

    • 两个相同的组件产生类似的DOM结构,不同的组件产生不同的DOM结构。
    • 同一层级的一组节点,他们可以通过唯一的id进行区分。基于以上这两点假设,使得虚拟DOM的Diff算法的复杂度从O(n^3)降到了O(n)。
  2. 仅在同级的vnode间做diff,递归地进行同级vnode的diff,最终实现整个DOM树的更新

结论

  1. 在渲染一组同级的VNode时,也遵循上述规则。所以当有key,在进行新旧VNode对比时可以很快的计算出那些项是没有变动的,没变动的这些可以复用旧VNode的数据。在真正的更新DOM时只更新变动的部分。让更新更加高效。

  2. 用Index做可以不推荐的原因比如有如下数据:

<ul>
  <li v-for="(item, index) in a" :key="index">{{a}}</li>
<ul>

data() {
  return {
    a: [1,2,3]
  }
}

上面的VNode可以表示为:

// VNode
[
  { tagName: 'li', key: 0, children: [1] },
  { tagName: 'li', key: 1, children: [2] }
  { tagName: 'li', key: 2, children: [3] }
]

如果在 a 数组 1 和 2 之间插入数字 4,此时的 a = [1,4,2,3], VNode如下:

// VNode
[
  { tagName: 'li', key: 0, children: [1] },
  { tagName: 'li', key: 1, children: [4] },
  { tagName: 'li', key: 2, children: [2] }
  { tagName: 'li', key: 3, children: [3] }
]

可以看到除了key=0可以复用外,其他项都不可复用,但是数据和之前是一样的。所以建议用Id作为key会更加高效。

@lvwxx lvwxx added the question Further information is requested label Aug 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

1 participant