普通根组件中 未带key的时候
html代码:
<div id="example14">
<!-- 新创建的dom 会有什么特点-->
<!-- 新dom 会触发动画 animation (此处知识点不牢)-->
<ul>
<li class="animate__animated animate__bounce" v-for="testData in testList"
>{{testData}}</li>
</ul>
<p>
<button @click="testList.push(`${testList.length}、测试数据`)">在后尾增加元素</button>
<button @click="testList.pop()">在后尾弹出元素</button>
<button @click="testList.unshift(`前方增加测试数据`)">在前方增加元素</button>
<button @click="testList.shift()">在前方弹出元素</button>
</p>
<p>这个里边的所有li 都是新渲染出来的 所以 这个虚拟DOM在渲染时 将调用生命周期钩子 所以这个元素将触发动画</p>
<p>现在的情况下是没有任何key绑定的</p>
<ol>
<li>后方增加元素、前方增加元素都是 在列表的最后尾创建 虚拟dom< /li>
<li>在原有模式下,点击前后方增加数据 都会在最后添加:以前面添加数据为例-> 第一位置给最新的数据,接着原来的第一位置在第二 依次往后走 最后数据排不开 再建一行</li>
</ol>
</div>
js代码:
Vue.createApp({
data(){
const testList = Array(10).fill(undefined);
testList.forEach((_,index,array)=>{
array[index] = `${index + 1}、测试数据`
});
return {testList};
},
}).mount('#example14')
在这里即使添加了key 但是key绑定为index 经过测试跟没加key一样
html代码:
<div id="example15">
<ul>
<li class="animate__animated animate__bounce" v-for="(testData,index) in testList" :key="testData.id">{{testData.value}}</li>
</ul>
<p>这时候就有问题了!</p>
<ol>
<li>先说这个 :key 是一个index 以第一个元素为例: index :0 </li>
<li>如果该 :key 被绑定在这个虚拟DOM元素上,我在列表前方增加一个元素</li>
<li>这个新增元素的index 将会变为0, key值在检测的时候,整个列表被更新</li>
<li>以上问题证明:这个key 就是绑定到虚拟DOM元素上的</li>
<li>解决方案 绑定key为一个固定值</li>
</ol>
<p>
<button @click="testList.push(createDataItem(`后方增加测试数据`))">在后尾增加元素</button>
<button @click="testList.pop()">在后尾弹出元素</button>
<button @click="testList.unshift(createDataItem(`前方增加测试数据`))">在前方增加元素</button>
<button @click="testList.shift()">在前方弹出元素</button>
<button @click="testList.splice(Math.floor(testList.length/2),0,createDataItem(`中间增加测试数据`))">中间增加测试数据</button>
</p>
<p>如果当前你要循环的数据为一个Array数组 嵌套Object对象,那么我么需要在Object对象中 设立唯一的标题key</p>
</div>
js代码:
Vue.createApp({
data(){
const testList = Array(10).fill(undefined);
// testList.forEach((_,index,array)=>{
// array[index] = `${index + 1}、测试数据`
// });
//Symbol 版本
testList.forEach((_,index,array)=>{
array[index] = {id:Symbol(''),value:`${index + 1}、测试数据`}
});
return {testList}
},
methods:{
createDataItem(text){
return {id:Symbol(),value:text}
}
}
}).mount('#example15')
子组件版本
html代码:
<div id="example16">
<p>使用 子组件的生命周期 来测试当前子组件是否被重用</p>
<ul>
<li is="vue:key-component" v-for="test_data in testList" :text="test_data.value" @create-component="createComponent" class="animate__animated animate__bounce"></li>
</ul>
<p>创建行为日志:</p>
<ol>
<li v-for="log in createComponentLog">行为日志明细---{{log}}</li>
</ol>
<p>
<button @click="testList_push">在后尾增加元素</button>
<button @click="testList.pop()" class="pop">在后尾弹出元素</button>
<button @click="testList_unshift">在前方增加元素</button>
<button @click="testList.shift()" class="shift">在前方弹出元素</button>
<button @click="testList_splice">中间增加测试数据</button>
</p>
<h4>这个子组件版本 没有使用key 测试结果跟</h4>
</div>
js代码:
// 单独列出来的 组件
const KeyComponent = {
name:'KeyComponent',
props:['text'],
emits:['create-component'],
created() {
this.$emit('create-component',`创建子组件,填充内容为:${this.text} `)
},
template:`<li>{{text}}</li>`
}
//子组件 不带key版本
Vue.createApp({
data(){
const testList = Array(10).fill(undefined);
// testList.forEach((_,index,array)=>{
// array[index] = `${index + 1}、测试数据`
// });
//Symbol 版本
testList.forEach((_,index,array)=>{
array[index] = {id:Symbol(''),value:`${index + 1}、测试数据`}
});
return {testList,createComponentLog:Array()}
},
components:{KeyComponent},
methods:{
createComponent(event){
this.createComponentLog.push(event)
},
testList_push(){
console.log('进入后尾添加')
this.testList.push({id:Symbol(''),value:`在后尾添加的元素`})
},
testList_unshift(){
console.log('进入前面添加函数')
this.testList.unshift({id:Symbol(''),value:`在前面添加的元素哈哈哈~`})
},
testList_splice(){
console.log('进入中间添加数据函数')
this.testList.splice(Math.floor(this.testList.length/2),0,{id:Symbol(''),value:'中间添加的数据yo~'})
}
}
}).mount('#example16')
子组件带key版
html代码:
<div id="example17">
<ul>
<li is="vue:use-key-component" v-for="test_data in testList" :text="test_data.value" :key="test_data.id" class="animate__animated animate__bounce" @create-component="createComponent"></li>
<hr>
<li v-for="test_data in testList">单独列出id值:{{test_data.id}}</li>
</ul>
<p>创建行为日志(只有添加 没有删除的详情)</p>
<ol>
<li v-for="log in createComponentLog">添加行为日志明显--{{log}}</li>
</ol>
<p>
<button @click="testList_push">在后尾增加元素</button>
<button @click="testList.pop()" class="pop">在后尾弹出元素</button>
<button @click="testList_unshift">在前方增加元素</button>
<button @click="testList.shift()" class="shift">在前方弹出元素</button>
<button @click="testList_splice">中间增加测试数据</button>
</p>
</div>
js代码:
const useKeyComponent = {
name:'useKeyComponent',
props:['text','key'],
emits:['create-component'],
created() {
this.$emit('create-component',`创建子组件,填充内容为:${this.text}--${this.key}`)
},
template:`<li>{{text}}</li>`
}
//子组件 带key 版本
Vue.createApp({
data(){
const testList = Array(10).fill(undefined);
//Symbol 版本
testList.forEach((_,index,array)=>{
array[index] = {id:Symbol(index),value:`${index + 1}、测试数据`}
});
console.log(testList)
return {testList,createComponentLog:Array()}
},
components:{useKeyComponent},
methods:{
//增加日志详情
createComponent(event){
this.createComponentLog.push(event)
},
testList_push(){
this.testList.push({id:Symbol(''),value:`在后尾添加的元素`})
},
testList_unshift(){
this.testList.unshift({id:Symbol(''),value:`在前面添加的元素哈哈哈~`})
},
testList_splice(){
this.testList.splice(Math.floor(this.testList.length/2),0,{id:Symbol(''),value:'中间添加的数据yo~'})
}
}
}).mount('#example17')
diff算法的本质是:
找出新旧两个虚拟dom对象之间的差异,目的是尽可能复用节点,提高性能。 key的主要作用就是在diff算法中判断新旧节点是否是同一类型,从而复用与新节点对应的老节点,节约性能的开销 知识点链接: blog.csdn.net/zl_Alien/ar…