05-Vue监测数据原理

在这里插入图片描述

前言

📋前言📋
💝博客:【无聊大侠hello word】💝
✍有一点思考,有一点想法,有一点理性!✍
✍本文由在下【无聊大侠hello word】原创,首发于CSDN✍

Vue监视数据改变

问题:

<body>
    <div id="app">
        <h2>人员列表</h2>
        <!-- 点击按钮后,马冬梅信息变成马老师 -->
        <button @click="updateMei">更新马冬梅信息</button>
        <ul>
            <li v-for="(p,index) of persons">
                {{p.name}}-{{p.age}}-{{p.sex}}
            </li>
        </ul>
    </div>
</body>
<script>
    Vue.config.productionTip = false;
    const vm = new Vue({
        el: '#app',
        data: {
            persons: [
                {id:'001', name:'马冬梅', age: 19, sex:'女'},
                {id:'002', name:'周冬雨', age: 20, sex:'女'},                
                {id:'004', name:'温兆伦', age: 22, sex:'男'},
                {id:'003', name:'周杰伦', age: 21, sex:'男'}
            ]
        },
        methods: {
            updateMei() {
                this.persons[0].name = '马老师';
                this.persons[0].age = 50;
                this.persons[0].sex = '男';
            }
        },
    });
</script>

但是当updateMei()改成直接修改数组时,Vue就监测不到了:

methods: {
    updateMei() {
        // 数组对象正常被修改了,但是Vue监测不到
        this.persons[0] = {id:'001', name:'马老师', age: 50, sex:'男'}
    }
},

手写数据代理

模仿vue的new Vue数据代理:

let data = {
    name: '张三',
    age: 10
};

const obs = new Observer(data);

// 准备一个vm实例
let vm = {};
vm._data = data = obs;
console.log(vm);

function Observer(obj) {
    const keys = Object.keys(obj);
    keys.forEach((k) => {
        Object.defineProperty(this, k, {
            get() {
                return obj[k];
            },
            set(val) {
                console.log(`${k}被修改了`)
                obj[k] = val;
            }
        })
    })
}

此时vm._data和传入的用户data完全一样,当vm._data里面的属性修改时,马上就可以被对应的setter捕获到,可以在setter中进行方法增强。

相比vue,还缺少的功能:

  1. vue中,除了可以用vm._data.age操作属性修改,还可以直接使用vm.age等操作属性修改
  2. vue中,data的属性可以是对象,vue使用了递归获取data所有层级的属性。

Vue的set()方法

Vue中,data的一级属性如果缺少会报错,但是二级属性如果缺少则不会报错。因为二级属性如果缺少会变成undefined,vue默认把undefined处理为空。

例如:

<div id='app'>
    <!-- data中没有直接的teacher属性,此处会报错 -->
    <h2>{{teacher}}</h2>
    <!-- data中存在student属性,但是student不存在age属性,此时不会报错,只是显示为空 -->    
    <h2>{{student.age}}</h2>
</div>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            student: {
                name: 'tom'
            }
        }
    })
</script>

此时,如果要为student对象添加age属性,使用js直接添加Vue不识别,不是响应式的属性:

// 下面两种写法,虽然可以给student对象正常添加上age属性,但是vue不识别,vue不会给添加的age属性生成setter/getter
vm._data.student.age = 18;
vm.student.age = 18;

vue提供了set()方法可以动态添加vue识别的响应式属性:

// 参数:target、添加的属性、属性值
// 这样为student添加的sex属性,和之前的name属性没有区别,也一样有setter、getter
Vue.set(vm.student, 'sex', 18);
// 或者使用vm的$set方法
vm.$set(vm.student, 'sex', 18);

vue的`set()``方法只能给data的二级属性添加属性,不能直接给data添加属性:

// 此时会报错,只能给data的二级属性添加属性,不能直接添加到data上
Vue.set(vm._data, 'address', 'China');
// 所以,set方法的第一个参数不能是vm/vm._data

Vue中数组数据监测

Vue不会对数组对象的数组元素生成setter、getter,所以数组元素直接修改时Vue监测不到。

const vm = new Vue({
    data: {
        student: {
            name: 'tom',
            friends:['jarry', 'tonny', 'marry']
        }
    }
});

// 数组第0个元素的值正常修改成了jany,但是vue监测不到这个变化,页面还是会展示jarry。
// 因为数组的索引值不会被生成getter/setter
vm._data.student.friends[0] = 'jany';

但是,调用js中操作数组的对应方法去修改数组数据,vue就可以正常监测到了:

  • push:在末尾追加
  • pop:删除最后一个元素
  • shift:删除第一个元素
  • unshift:数组头上插入一个元素
  • splice:在指定位置插入/替换元素
  • sort:数组排序
  • revese

因为filter方法不会影响原数组的元素,所以没有filter。

对象数组使用者几个方法添加修改元素时,添加上来的也是响应式的。

const vm = new Vue({
    data: {
        student: {
            friends:[
                {name: 'jerry', age: 20},
                {name: 'tony', age:26}
            ],
            hobby: ['踢球', '看电视', '听音乐']
        }
    },
    method: {
        addSex() {
            // 向student添加一个属性sex
            this.$set(this.student, 'sex', '男');
        }
        addFriend() {
            // 向数组开头插入一个元素,添加进来的对象也可以正常修改里面的name、age
            this.student.friends.unshift({name: 'jack', age: 70})
        },
        updateFriend() {
            // 这里正常修改数组元素下的属性,vue也可以正常监测到
            this.student.friends[0].name = '张三';
        },
        addHobby() {
            // 向爱好数组中末尾添加一个元素
            this.student.hobby.push('读书');
        },
        updateHobby() {
            // 将第一个爱好改为开车
            this.student.hobby.splice(0, 1, '开车');
            // 或者使用set()方法,将数组对象的第0项改为开车
            // this.$set(this.student.hobby, 0, '开车');
        }
    }
});

Vue监视数据的原理

Vue会监视data中所有层次的数据。

通过setter实现监视,且要在 new Vue时就传入要监测的数据:

  • 对象中使用 js 直接追加的属性,vue默认不做响应式处理
  • 如果要给后添加的属性做响应式,需要使用对应的API
Vue.set(target, propertyName/index, val);
vm.$set(target, propertyName/index, val);

Vue对数组中数据的监视,通过包裹数组更新元素的方法(例如splica/push/pop等)实现,本质就是做了两件事:

  • 调用原生对应的方法对数组进行更新
  • 重新解析模板,进行更新页面

在Vue修改数组中的某个元素一定要使用如下方法:

  • pushpopshiftunshiftsplicesortreverse
  • 或者使用:Vue.set()vm.$set()

Vue.set()vm.$set()不能给vm或者vm的根数据对象添加属性,即方法的第一个参数不能是vm/vm._data

先赞后看,养成习惯!!!^ _ ^ ❤️ ❤️ ❤️
码字不易,大家的支持就是我的坚持下去的动力。点赞后不要忘了关注我哦!

### 回答1: Vue数据监测的原理是利用了JavaScript的Object.defineProperty()方法,通过对数据对象进行劫持,对其属性的读取和修改进行监听和拦截,从而实现数据响应式的效果。当数据发生变化时,Vue会自动检测到变化并通知相关的视图进行更新,从而实现数据和视图的自动同步。同时,Vue还提供了一些API,如$watch和computed等,方便开发者对数据变化进行手动监听和处理。 ### 回答2: Vue数据监测的原理是通过使用Object.defineProperty()方法对数据对象进行劫持和监听,实现对数据变化进行监测。在Vue的实例化过程中,会遍历所有的数据对象,将每个属性转化为getter和setter来实现数据的劫持。 当数据被访问时,会触发getter函数,在getter函数中可以进行依赖收集,将当前正在执行的Watcher对象添加到依赖列表中。当数据被修改时,会触发setter函数,setter函数会通知依赖列表中的Watcher对象更新视图。 在getter函数中进行依赖收集的关键是通过Dep(依赖收集器)来实现的。每个属性对应一个Dep对象,在getter函数中会通过Dep.target属性存储当前的Watcher对象,然后将该Watcher对象添加到Dep对象的依赖列表中。而Watcher对象是在Vue的编译阶段创建的,一个Watcher对象实际上包含了一个用户定义的回调函数(用于更新视图)以及关联的组件实例。 在数据对象被修改时,setter函数会被触发,这时会通知Dep对象的notify()方法去通知所有的Watcher对象进行更新操作。在更新过程中,Watcher会重新执行页面渲染的操作,将修改后的数据更新到视图上。 总结来说,Vue数据监测的原理是通过Object.defineProperty()方法将数据对象的属性转化为getter和setter,在getter函数中进行依赖收集,在setter函数中通知依赖进行更新。这样就实现了数据和视图的双向绑定,使得数据变化能够自动更新到对应的视图上。 ### 回答3: Vue数据监测原理是通过使用数据劫持结合发布-订阅模式来实现的。 首先,在Vue创建实例时,所有的data属性会被Vue转化成getter和setter的形式,并使用Object.defineProperty()进行劫持。 接下来,当访问或修改data属性时,Vue会收集相关依赖。当属性被读取时,会触发getter函数,将依赖收集到当前的依赖列表中;当属性被修改时,会触发setter函数,通知依赖更新。 然后,Vue利用发布-订阅模式建立了一个观察者(Watcher)与数据(data)之间的依赖关系。当依赖发生变化时,会通知相应的观察者进行更新操作。 另外,为了减少不必要的依赖收集和更新操作,Vue还进行了一些优化。Vue使用异步更新策略将多次数据变化的更新合并为一次更新,避免频繁的DOM操作。同时,还对监听数据进行了缓存,当多次访问同一个属性时,只会收集依赖一次。 总结起来,Vue数据监测原理是通过数据劫持结合发布-订阅模式实现的。通过定义getter和setter来劫持属性,收集依赖并建立观察者与数据之间的依赖关系。当依赖发生变化时,触发相应的更新操作。同时,还进行了一些优化措施来提高性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值