有关于vue中的key

81 阅读2分钟

普通根组件中 未带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 以第一个元素为例: index0  </li>
        <li>如果该 :key 被绑定在这个虚拟DOM元素上,我在列表前方增加一个元素</li>
        <li>这个新增元素的index 将会变为0key值在检测的时候,整个列表被更新</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…