小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
1. 详解 v-for 的 key
1.1 v-for 中的 key 的作用
在使用 v-for 进行列表渲染时,我们通常会给元素或组件绑定一个 key 属性。
这个 key 属性有什么作用呢?我们先来看下官方的解释:
key属性主要用做Vue的虚拟DOM算法的提示,以便在对比新旧节点组时辨识VNodes;- 如果不使用
key,Vue会使用一种算法来最小化元素的移动并且尽可能尝试就地修改/复用相同类型元素; - 而使用
key时,它会基于key的顺序变化重新排列元素,并且key不再存在的元素将始终被移除/销毁。
官方的解释对于初学者来说并不好理解,比如下面的问题:
- 什么是新旧节点组?什么是
VNode? - 没有
key时,如何尝试修改和复用的? - 有
key时,如何基于key重新排列的?
1.2 认识 VNode
先来解释一下 VNode 的概念:
- 因为目前我们还没有比较完整的学习组件的概念,所以我们暂时先理解
HTML元素创建出来的VNode; VNode即Virtual Node,也就是虚拟节点(其实是存在内存中的JavaScript对象。相对的,诸如<html>、<body>、<div>、<p>等DOM节点就是真实节点);- 事实上,无论元素还是组件,最终在
Vue中表示出来的都是一个个的VNode; VNode的本质就是一个JavaScript对象。
假设我们有以下元素:
<div class="title" style="font-size: 30px; color: red;">哈哈哈</div>
它经过 Vue 处理后会转换成一个 VNode,是一个 JavaScript 对象,主要内容如下:
const vnode = {
type: "div",
props: {
class: "title",
style: {
"font-size": "30px",
color: "red"
}
},
children: "哈哈哈"
}
如果上面 <div> 元素中放的不是文本,而是其它多个元素,那么这多个元素又会分别创建对应的 VNode,然后组成一个 VNode 数组赋值给 <div> 元素对应的 VNode 对象的 children 属性。
创建 VNode 的代码可以在 Vue 源码的 packages/runtime-core/src/vnode.ts 文件中看到:函数 _createVNode() 会返回一个 vnode 对象,这个对象中有很多属性,包括 type、props、children。具体的创建过程我们也可以去调试源码查看。
总之,模板里面的元素最终会转成一个一个的 VNode,再由这些 VNode 转换成真实的 DOM,然后我们才可以在浏览器页面中看到真实 DOM 呈现的内容:
多了中间这一步,主要的好处是便于做多平台的渲染:我们可以利用 VNode 做服务端的渲染,也可以用 VNode 做移动端的渲染,还可以用 VNode 做浏览器的渲染。除了做跨平台,在某些情况下,使用 VNode (虚拟 DOM)还可以有更高一点的性能。