列表渲染:进阶

:key="index",key唯一,专门给节点一个标识,无法重复,否则报错

虚拟DOM对比算法:将初始虚拟DOM和新虚拟DOM进行对比

流程:首先来到新的虚拟DOM处,取出新的虚拟DOM的key,随后来到初始的虚拟DOM处,来找和新虚拟DOM一样key的数据

初始虚拟DOM(部分):

<li key="0">张三-18<input type='text'><li>
<li key="1">李四-19<input type='text'><li>

新虚拟DOM(部分),添加一条数据:

<li key="0">老李-30<input type='text'><li>
<li key="1">张三-18<input type='text'><li>
<li key="2">李四-19<input type='text'><li>

旧:张三-18

新:老李-30

这一段不同,而后面的<input type='text'>是相同的

总而言之:

对比相同的部分:复用到新的真实DOM上

对比不同的部分:旧的无法复用,只能将新的虚拟DOM中的东西转为一个新的DOM节点,那么就会出现以下情况:

前面的变为老李-30,但是后面的输入框中的内容不变,没有跟随张三-18那一行

总的来说:新的DOM中,老李-30,张三-18,李四-19都是新生成的,老李30,张三18的输入框是复用而来的

李四19的输入框是新生成的

而是用key进行唯一标识,得到的key会逐行检查是否存在对应的标识,如果没有,则全盘进行从新生成,不会只生成半边复用半边的情况

如果有,则直接复用旧的虚拟DOM中的内容并牵引到新的DOM中

还有一种情况就是没有写key,这种情况下,Vue会自动用循环索引补齐key,那就和自己确定index一样了

当index作为key

当id作为key

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>你好啊!</title>
    <script type="text/javascript" src="../JS/vue.js"></script>
</head>

<body>
    <div id="root">
        <button @click.once="add">添加一个老刘</button>
        <ul>
            <!-- 
                key是vue内部在使用,我们不能使用
            -->
<!-- 
            这种写法有问题,在完成输入框输入之后再按按钮,会发现错乱问题
            index是循环的索引

            <li v-for="(p,index) in personList" :key="index">
                {{p.name}}-{{p.age}}
                <input type="text">
            </li>
 -->
<!--  -->
            <li v-for="p in personList" :key="p.id">
                {{p.name}}-{{p.age}}
                <input type="text">
            </li>
        </ul>

    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false;
        new Vue({
            el: "#root",
            data: {
                personList:[
                    { id: '001', name: '张三', age: 18 },
                    { id: '002', name: '老李', age: 19 },
                    { id: '003', name: '王五', age: 20 },
                ],
            },
            methods: {
                add(){
                    const p = {
                        id: '004',
                        name: '老刘',
                        age: 40
                    }
                    this.personList.unshift(p)
                }
            },
        })
    </script>
</body>

</html>

总结:

react,vue的key有什么作用(key的内部原理)

1,虚拟DOM中key的作用:

    key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据[新数据]生成[新的虚拟DOM]

    随后Vue进行[新虚拟DOM],[旧虚拟DOM]的差异比较,比较规则如下:

2,对比规则:

    旧虚拟DOM中找到了和新虚拟DOM相同的key:

        若虚拟DOM中内容不变,直接使用之前的真实DOM

        若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM

3,用index作为key可能会引发的问题:

    1,若对数据进行:逆序添加,逆序删除等破坏顺序的操作:

            会产生没有必要的真实DOM更新==>界面效果没有问题,但是效率低下

    2,如果数据中还包含输入类的DOM:

            会产生错误DOM更新===>界面有问题

4,开发中如何选择key:

        1,最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号等唯一值

        2,如果不存在对数据的逆序添加,逆序删除等破坏顺序的操作,仅用于渲染列表用于展示,使用index作为key是没有问题的


列表过滤

对一个字符串使用indexOf(),用来查询是否存在

const str='abc'

str.indexOf('x') 此时得到的值为-1,因为没有找到x这个字符

如果包含要搜寻的字符,那么它就会返回这个字符的位置,

str.indexOf('a') 得到的值为0

注意:str.indexOf('') 空字符串,得到的是0而非-1

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>你好啊!</title>
    <script type="text/javascript" src="../JS/vue.js"></script>
</head>

<body>
    <div id="root">
        <h2>人员列表</h2>
        <!-- 模糊搜索 -->
        <input type="text" placeholder="请输入姓名" v-model="keyWord">
        <ul>
            <li v-for="p in filPersonList" :key="p.id">
                {{p.name}}-{{p.age}}-{{p.sex}}
            </li>
        </ul>

    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false;
        // #region
        // const vm = new Vue({
        //     el: "#root",
        //     data: {
        //         keyWord:'',
        //         personList:[
        //             { id: '001', name: '马冬梅', age: 19, sex: '女' },
        //             { id: '002', name: '周冬雨', age: 20, sex: '女' },
        //             { id: '003', name: '周杰伦', age: 21, sex: '男' },
        //             { id: '004', name: '温兆伦', age: 22, sex: '男' },
        //         ],
        //         filPersonList:[],
        //     },
        //     watch:{
        //         keyWord:{
        //             immediate:true,
        //             handler(newValue, oldValue) {
        //                 console.log('keyWord被修改', newValue)
        //                 // 通过filter会得到一个新的数组,需要其将旧数组覆盖,但这样也有坏处,过滤掉的数组成员将不再回来
        //                 // 也就是彻底丢失了,到后面越搜索越少,注意,不要随便修改personList这个数组
        //                 this.filPersonList = this.personList.filter((p) => {
        //                     return p.name.indexOf(newValue) !== -1
        //                 })//根据条件将符合的数据过滤出来
        //             }
        //         }
        //     },
        // })
        // #endregion

        // 使用computed实现
        const vm = new Vue({
            el: "#root",
            data: {
                keyWord:'',
                personList:[
                    { id: '001', name: '马冬梅', age: 19, sex: '女' },
                    { id: '002', name: '周冬雨', age: 20, sex: '女' },
                    { id: '003', name: '周杰伦', age: 21, sex: '男' },
                    { id: '004', name: '温兆伦', age: 22, sex: '男' },
                ],
            },
            computed:{
                filPersonList(){
                    return this.personList.filter((p) => {
                        return p.name.indexOf(this.keyWord) !== -1
                    })
                }
            }
        })
    </script>
</body>

</html>

列表排序

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>你好啊!</title>
    <script type="text/javascript" src="../JS/vue.js"></script>
</head>

<body>
    <div id="root">
        <h2>人员列表</h2>
        <!-- 模糊搜索 -->
        <input type="text" placeholder="请输入姓名" v-model="keyWord">
        <button @click="sortType=2">年龄升序</button>
        <button @click="sortType=1">年龄降序</button>
        <button @click="sortType=0">原顺序</button>
        <ul>
            <li v-for="p in filPersonList" :key="p.id">
                {{p.name}}-{{p.age}}-{{p.sex}}
            </li>
        </ul>

    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false;

        // 使用computed实现
        const vm = new Vue({
            el: "#root",
            data: {
                keyWord:'',
                sortType:0,//0代表原顺序,1代表降序,2代表升序
                personList:[
                    { id: '001', name: '马冬梅', age: 25, sex: '女' },
                    { id: '002', name: '周冬雨', age: 24, sex: '女' },
                    { id: '003', name: '周杰伦', age: 33, sex: '男' },
                    { id: '004', name: '温兆伦', age: 30, sex: '男' },
                ],
            },
            computed:{
                filPersonList(){
                    const arr = this.personList.filter((p) => {
                        return p.name.indexOf(this.keyWord) !== -1
                    })
                    //判断是否需要排序
                    if(this.sortType!==0){
                        arr.sort((p1,p2)=>{
                            return this.sortType===1?p2.age-p1.age:p1.age-p2.age
                        })
                        // sort可以改变原数组,谁.sort就是对谁排序,数组本身会发生改变
                    }

                    return arr
                }
            }
        })
        // let arr = [1,5,3,6,8,2]
        // arr.sort((a,b)=>{
        //     return a-b;//此为升序排序
        //     // return b-a;//此为降序排序
        // })
        // console.log(arr)
    </script>
</body>

</html>

这个家伙很懒,什么也没留下