Vue
의 특수
속성
은 주로 Vue 가상화에 사용됩니다.
DOM
알고리즘은 이전 노드
를 비교할 때 VNodes
를 식별합니다. 가 사용되지 않으면
Vue
는 동적 요소를 최소화하고 동일한 유형의 요소를 최대한 수정하고 재사용하려고 시도하는 알고리즘을 대신 사용합니다. >key
, 변경에 따라 요소 순서를 재정렬하고
가 존재하지 않는 요소를 제거합니다. 또한 동일한 상위 요소가 있는 하위 요소에는 고유한
키
가 있어야 합니다. 키
가 중복되면 렌더링 오류가 발생합니다. 的特殊
attribute
主要用在Vue
的虚拟DOM
算法,在新旧Nodes
对比时辨识VNodes
。如果不使用,
Vue
会使用一种最大限度减少动态元素并且尽可能的尝试就地修改、复用相同类型元素的算法,而使用时,它会基于
的变化重新排列元素顺序,并且会移除
不存在的元素。此外有相同父元素的子元素必须有独特的
,重复的
会造成渲染错误。
相关学习推荐:javascript视频教程
描述
首先是官方文档的描述,当Vue
正在更新使用v-for
渲染的元素列表时,它默认使用就地更新的策略,如果数据项的顺序被改变,Vue
将不会移动DOM
元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时DOM
状态的列表渲染输出,例如表单输入值。为了给Vue
一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 ,建议尽可能在使用
v-for
时提供,除非遍历输出的
DOM
内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
简单来说,当在列表循环中使用时,需要使用
来给每个节点做一个唯一标识,
diff
算法就可以正确的识别此节点,找到正确的位置直接操作节点,尽可能地进行重用元素,的作用主要是为了高效的更新虚拟
DOM
。此外,使用index
作为是并不推荐的做法,其只能保证
Vue
在数据变化时强制更新组件,以避免原地复用带来的副作用,但不能保证最大限度的元素重用,且使用index
作为在数据更新方面和不使用
的效果基本相同。
示例
首先定义一个Vue
实例,渲染四个列表,分别为简单列表与复杂列表,以及其分别携带与不携带
时对比其更新渲染时的速度,本次测试使用的是
Chrome 81.0
,每次在Console
执行代码时首先会进行刷新重新加载界面,避免浏览器以及Vue
自身优化带来的影响。
<!DOCTYPE html> <html> <head> <title>Vue</title> </head> <body> <p id="app"> <ul> <li v-for="item in simpleListWithoutKey" >{{item}}</li> </ul> <ul> <li v-for="item in simpleListWithKey" :key="item" >{{item}}</li> </ul> <ul> <li v-for="item in complexListWithoutKey"> <span v-for="value in item.list" v-if="value > 5">{{value}}</span> </li> </ul> <ul> <li v-for="item in complexListWithKey" :key="item.id"> <span v-for="value in item.list" :key="value" v-if="value > 5">{{value}}</span> </li> </ul> </p> </body> <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script> <script type="text/javascript"> var vm = new Vue({ el: '#app', data: { simpleListWithoutKey: [1, 2, 3, 4, 5, 6], simpleListWithKey: [1, 2, 3, 4, 5, 6], complexListWithoutKey:[ {id: 1, list: [1, 2, 3]}, {id: 2, list: [4, 5, 6]}, {id: 3, list: [7, 8, 9]} ], complexListWithKey:[ {id: 1, list: [1, 2, 3]}, {id: 2, list: [4, 5, 6]}, {id: 3, list: [7, 8, 9]} ], } }) </script> </html>
简单列表
在简单列表的情况下,不使用可能会比使用
的情况下在更新时的渲染速度更快,这也就是官方文档中提到的,除非遍历输出的
DOM
内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。在下面的例子中可以看到没有的情况下列表更新时渲染速度会快,当不存在
的情况下,这个列表直接进行原地复用,原有的节点的位置不变,原地复用元素,将内容更新为
5
、6
、7
、8
、9
、10
,并添加了11
与12
两个节点,而存在的情况下,原有的
1
、2
、3
、4
节点被删除,5
、6
节点保留,添加了7
、8
、9
、10
、11
、12
六个节点,由于在DOM
的增删操作上比较耗时,所以表现为不带的情况下速度更快一些。
// 没有key的情况下 console.time(); vm.simpleListWithoutKey = [5, 6, 7, 8, 9, 10, 11, 12]; vm.$nextTick(() => console.timeEnd()); // default: 2.193056640625ms
// 存在key的情况下 console.time(); vm.simpleListWithKey = [5, 6, 7, 8, 9, 10, 11, 12]; vm.$nextTick(() => console.timeEnd()); // default: 3.2138671875ms
原地复用可能会带来一些副作用,文档中提到原地复用这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时DOM
관련 학습 권장사항: 자바스크립트 동영상 튜토리얼🎜🎜🎜🎜Description🎜🎜🎜🎜첫 번째는 공식 문서의 설명으로,
Vue
가 v-for 내부 업데이트 전략, 데이터 항목의 순서가 변경되면 <code>Vue
는 데이터 항목의 순서와 일치하도록 DOM
요소를 이동하지 않고 각 요소를 업데이트합니다. in-place 요소를 사용하고 각 인덱스 위치에서 올바르게 렌더링되는지 확인하세요. 이 기본 모드는 효율적이지만 하위 구성 요소 상태나 임시 DOM
상태(예: 양식 입력 값)에 의존하지 않는 목록 렌더링 출력에만 적합합니다. 각 노드의 ID를 추적하여 기존 요소를 재사용하고 재정렬할 수 있도록 Vue
에 힌트를 제공하려면 고유한 을 제공해야 합니다. 출력 DOM
을 순회하는 것이 매우 간단하지 않은 한, 가능하면 v-for
를 사용할 때 을 제공하는 것이 좋습니다. 콘텐츠를 사용하거나 의도적으로 기본 동작을 사용하여 성능을 향상시킵니다. 🎜🎜간단히 말하면, 목록 루프에서 를 사용할 때 각 노드를 고유하게 식별하려면 를 사용해야 합니다. diff
알고리즘은 올바르게 이 노드를 식별하고 올바른 위치를 찾아 노드를 직접 작동하고, 요소를 최대한 재사용하는 것이 의 주요 역할은 가상 DOM
을 효율적으로 업데이트하는 것입니다. 또한 index
를 로 사용하는 것은 권장되지 않습니다. 이는 데이터가 변경될 때 Vue
가 구성 요소를 강제로 업데이트하도록 보장할 뿐입니다. 로컬 재사용으로 인해 원래 부작용이 발생했지만 최대 요소 재사용을 보장할 수 없으며 데이터 업데이트에서 index
를 로 사용하고 를 사용하지 마세요. 효과는 기본적으로 동일합니다. 🎜🎜🎜🎜Example🎜🎜🎜🎜먼저 Vue
인스턴스를 정의하고 4개의 목록, 즉 단순 목록과 복합 목록, 키
를 전달하는 목록과 를 사용할 때의 업데이트 속도와 렌더링 속도를 비교해보세요. 에서 코드가 실행될 때마다 먼저 실행되는 <code>Chrome 81.0
을 사용합니다. 콘솔
브라우저와 Vue
자체 최적화의 영향을 피하기 위해 인터페이스를 새로 고치고 다시 로드합니다. 🎜<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>就地复用</title>
</head>
<body>
<p id="app">
<h3>采用就地复用策略(vuejs默认情况)</h3>
<p v-for='(p, i) in persons'>
<span>{{p.name}}<span>
<input type="text"/>
<button @click='down(i)' v-if='i != persons.length - 1'>下移</button>
</p>
<h3>不采用就地复用策略(设置key)</h3>
<p v-for='(p, i) in persons' :key='p.id'>
<span>{{p.name}}<span>
<input type="text"/>
<button @click='down(i)' v-if='i != persons.length - 1'>下移</button>
</p>
</p>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
persons: [
{ id: 1, name: 'A' },
{ id: 2, name: 'B' },
{ id: 3, name: 'C' }
]
},
mounted: function(){
// 此DOM操作将两个A的颜色设置为红色 主要是为了演示原地复用
document.querySelectorAll("h3 + p > span:first-child").forEach( v => v.style.color="red");
},
methods: {
down: function(i) {
if (i == this.persons.length - 1) return;
var listClone = this.persons.slice();
var one = listClone[i];
listClone[i] = listClone[i + 1];
listClone[i + 1] = one;
this.persons = listClone;
}
}
});
</script>
</body>
</html>
<!-- 源于 https://www.zhihu.com/question/61078310 @霸都丶傲天 有修改-->
🎜🎜🎜간단한 목록🎜🎜🎜🎜간단한 목록의 경우 를 사용하는 것보다 를 사용하지 않는 것이 업데이트 시 더 빠르게 렌더링될 수 있습니다. Fast, 이것이 바로 출력 DOM
콘텐츠를 순회하는 것이 매우 간단하거나 의도적으로 기본 동작에 의존하여 성능 향상을 얻는 것이 아니라면 공식 문서에 언급되어 있습니다. 다음 예에서는 키
없이 목록을 업데이트하면 렌더링 속도가 더 빨라지는 것을 확인할 수 있습니다. 키
가 없으면 목록이 바로 그 자리에 복원됩니다. 를 사용하면 원래 노드의 위치는 변경되지 않고 요소는 제자리에 재사용되며 콘텐츠는 5
, 6
, 7
로 업데이트됩니다. >, 8
, 9
, 10
, 두 개의 노드 11
및 12
는 추가되었으며, 가 존재할 경우 원래 1
, 2
, 3
, 4
노드가 삭제되고, 5
, 6
노드가 유지되고, 7
, 8
, 9, <code>10
, 11
, 12
6개 노드를 추가했습니다. DOM
의 추가 및 삭제 작업은 다음과 같습니다. 상대적으로 시간이 많이 걸리므로 키
가 없으면 더 빠릅니다. 🎜console.time();
vm.complexListWithoutKey = [
{id: 3, list: [7, 8, 9]},
{id: 2, list: [4, 5, 6]},
{id: 1, list: [1, 2, 3]},
];
vm.$nextTick(() => console.timeEnd());
vm.$nextTick(() => console.timeEnd());
// default: 4.100244140625ms
console.time();
vm.complexListWithKey = [
{id: 3, list: [7, 8, 9]},
{id: 2, list: [4, 5, 6]},
{id: 1, list: [1, 2, 3]},
];
vm.$nextTick(() => console.timeEnd());
// default: 3.016064453125ms
🎜내부 재사용은 일부 부작용을 가져올 수 있습니다. 문서에서는 내부 재사용의 기본 모드가 효율적이라고 언급하지만 하위 구성 요소 상태 또는 임시 DOM에 의존하지 않는 상황에만 적합합니다.
상태. 양식 입력 값과 같은 렌더링된 출력 목록입니다. 🎜在不设置的情况下,元素中没有与数据data
绑定的部分,Vue
会默认使用已经渲染的DOM
,而绑定了数据data
的部分会进行跟随数据渲染,假如操作了元素位置,则元素中未绑定data
的部分会停留在原地,而绑定了data
的部分会跟随操作进行移动,在下面的例子中首先需要将两个A
之后的输入框添加数据信息,这样就制作了一个临时状态,如果此时点击下移按钮,那么不使用的组中的输入框将不会跟随下移,且B
到了顶端并成为了红色,而使用的组中会将输入框进行下移,且A
依旧是红色跟随下移。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>就地复用</title>
</head>
<body>
<p id="app">
<h3>采用就地复用策略(vuejs默认情况)</h3>
<p v-for='(p, i) in persons'>
<span>{{p.name}}<span>
<input type="text"/>
<button @click='down(i)' v-if='i != persons.length - 1'>下移</button>
</p>
<h3>不采用就地复用策略(设置key)</h3>
<p v-for='(p, i) in persons' :key='p.id'>
<span>{{p.name}}<span>
<input type="text"/>
<button @click='down(i)' v-if='i != persons.length - 1'>下移</button>
</p>
</p>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
persons: [
{ id: 1, name: 'A' },
{ id: 2, name: 'B' },
{ id: 3, name: 'C' }
]
},
mounted: function(){
// 此DOM操作将两个A的颜色设置为红色 主要是为了演示原地复用
document.querySelectorAll("h3 + p > span:first-child").forEach( v => v.style.color="red");
},
methods: {
down: function(i) {
if (i == this.persons.length - 1) return;
var listClone = this.persons.slice();
var one = listClone[i];
listClone[i] = listClone[i + 1];
listClone[i + 1] = one;
this.persons = listClone;
}
}
});
</script>
</body>
</html>
<!-- 源于 https://www.zhihu.com/question/61078310 @霸都丶傲天 有修改-->
复杂列表
使用不仅能够避免上述的原地复用的副作用,且在一些操作上可能能够提高渲染的效率,主要体现在重新排序的情况,包括在中间插入和删除节点的操作,在下面的例子中没有的情况下重新排序会原地复用元素,
但是由于v-if
绑定了data
所以会一并进行操作,在这个DOM
操作上比较消耗时间,而使用得情况则直接复用元素,v-if
控制的元素在初次渲染就已经决定,在本例中没有对其进行更新,所以不涉及v-if
的DOM
操作,所以在效率上会高一些。
console.time();
vm.complexListWithoutKey = [
{id: 3, list: [7, 8, 9]},
{id: 2, list: [4, 5, 6]},
{id: 1, list: [1, 2, 3]},
];
vm.$nextTick(() => console.timeEnd());
vm.$nextTick(() => console.timeEnd());
// default: 4.100244140625ms
console.time();
vm.complexListWithKey = [
{id: 3, list: [7, 8, 9]},
{id: 2, list: [4, 5, 6]},
{id: 1, list: [1, 2, 3]},
];
vm.$nextTick(() => console.timeEnd());
// default: 3.016064453125ms
위 내용은 Vue에서 키의 역할에 대한 자세한 코드 설명 예시의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!