Vue列表渲染与数据监测原理

一、v-for指令详解

v-for是Vue中最常用的指令之一,用于遍历展示列表数据。它的基本语法是:v-for="(val, key) in xxx" :key="key",其中in也可以替换为of

1.1 基本用法

v-for可以遍历多种数据类型:

人员列表

  • {{index}}:{{p.name}} - {{p.age}}

车辆信息

  • {{key}}:{{val}}

字符信息

  • {{index}}:{{char}}

数字

  • {{index}}:{{num}}

对应的JavaScript代码:

new Vue({
    el: '#app',
    data: {
        persons: [
            {id: '001', name: '张三', age: 18},
            {id: '002', name: '李四', age: 19},
            {id: '003', name: '王五', age: 20}
        ],
        car: {
            brand: '奔驰',
            price: '40万',
            color: '黑色'
        },
        str: 'hello'
    }
})

1.2 遍历不同数据类型的说明

  1. 数组:第一个参数是数组元素,第二个参数是索引

  2. 对象:第一个参数是属性值,第二个参数是属性名

  3. 字符串:第一个参数是字符,第二个参数是索引

  4. 数字:遍历从1开始到该数字的整数,第一个参数是数字值,第二个参数是索引

二、key的原理与重要性

2.1 虚拟DOM中key的作用

key是虚拟DOM对象的唯一标识,当数据发生变化时,Vue会执行以下步骤:

  1. 根据新数据生成新的虚拟DOM

  2. 将新虚拟DOM与旧虚拟DOM进行Diff算法比较

    • 如果找到相同key的节点:

      • 内容没变 → 直接复用之前的真实DOM

      • 内容变化 → 生成新的真实DOM替换旧的真实DOM

    • 如果没找到相同key的节点 → 创建新的真实DOM并渲染

2.2 使用index作为key的问题

  • {{p.name}}

假设我们有以下操作:

  1. 在列表开头添加一个新项

  2. 在输入框中输入一些内容

问题表现

  1. 会产生不必要的真实DOM更新,降低效率

  2. 输入框内容会出现错位(因为index变化导致输入框与数据对应关系错乱)

2.3 最佳实践

  1. 理想情况:使用数据的唯一标识作为key(id、手机号、身份证号等)

  • {{p.name}}
    1. 2. 简单场景:如果没有逆序增删等操作,可以使用index作为key

    三、列表过滤与排序

    3.1 列表过滤的实现方式

    方式一:使用watch实现
    new Vue({
        data: {
            keyword: '',
            persons: [...],
            filterPerson: []
        },
        watch: {
            keyword: {
                immediate: true,
                handler(newVal) {
                    this.filterPerson = this.persons.filter(p => {
                        return p.name.includes(newVal)
                    })
                }
            }
        }
    })
    方式二:使用computed实现(推荐)
    new Vue({
        data: {
            keyword: '',
            persons: [...]
        },
        computed: {
            filterPerson() {
                return this.persons.filter(p => {
                    return p.name.includes(this.keyword)
                })
            }
        }
    })

    3.2 列表排序的实现

    computed: {
        filterPerson() {
            let arr = this.persons.filter(p => {
                return p.name.includes(this.keyword)
            })
            
            if(this.sortType) {
                arr.sort((p1, p2) => {
                    return this.sortType === 1 
                        ? p2.age - p1.age  // 降序
                        : p1.age - p2.age  // 升序
                })
            }
            
            return arr
        }
    }

    四、Vue数据监测原理深度解析

    4.1 对象监测

    Vue会通过setter监视data中所有层次的对象属性:

    1. 初始化时定义:只有在new Vue时就存在的属性才会被监测

    2. 新增属性问题:后期添加的属性默认没有响应式

    vm.newProp = 'value' // 非响应式

        3. 解决方案:使用Vue.set或vm.$set

    Vue.set(vm.someObject, 'newProp', 'value')
    // 或
    this.$set(this.someObject, 'newProp', 'value')

    4.2 数组监测

    Vue通过重写数组的变更方法实现监测:

    1. 包裹的方法:push/pop/shift/unshift/sort/splice/reverse

    2. 原理

      • 调用原生数组方法更新数据

      • 重新解析模板,更新页面

    3. 注意事项

      • 直接通过索引修改数组元素不是响应式的

        vm.items[0] = newValue // 不是响应式的
      • 解决方案

      • Vue.set(vm.items, 0, newValue)
        // 或使用splice
        vm.items.splice(0, 1, newValue)

    4.3 数据劫持原理

    Vue在初始化时会对data进行"数据劫持":

    1. 使用Object.defineProperty将data属性转换为getter/setter

    2. 每个组件实例都有对应的watcher实例

    3. 当属性被访问或修改时,会触发getter/setter通知watcher

    4. watcher会触发组件重新渲染

     

    // 简化的数据劫持示例
    function observe(data) {
        if (!data || typeof data !== 'object') return
        
        Object.keys(data).forEach(key => {
            let value = data[key]
            Object.defineProperty(data, key, {
                get() {
                    console.log(`读取${key}: ${value}`)
                    return value
                },
                set(newVal) {
                    console.log(`设置${key}: ${newVal}`)
                    value = newVal
                }
            })
        })
    }

    五、实际应用案例

    5.1 动态表单实现

    5.2 性能优化技巧

    1. 避免大型列表:对于大型列表,考虑使用虚拟滚动(如vue-virtual-scroller)

    2. 避免不必要的响应式:冻结不需要响应式的大数据对象

    this.largeData = Object.freeze(largeData)
    1. 合理使用key:确保key的稳定性和唯一性

    六、总结

    1. v-for是Vue列表渲染的核心指令,支持多种数据类型

    2. key的正确使用对列表渲染性能和正确性至关重要

    3. 计算属性是实现列表过滤和排序的理想选择

    4. Vue的数据监测机制基于getter/setter和数组方法重写

    5. 对于动态添加的属性,需要使用Vue.set保证响应式

    理解这些核心概念,能够帮助开发者编写更高效、更可靠的Vue应用程序。在实际项目中,合理应用这些知识可以避免许多常见的性能问题和bug。

    你可能感兴趣的:(vue.js,javascript,前端)