本篇内容介绍了“Vue3响应式原理实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
回顾 vue2.x 的响应式
实现原理:
对象类型:通过
object.defineProperty()
对属性的读取、修改进行拦截(数据劫持)数组类型:通过重写更新数组的一系列方法来实现拦截(对数组的变更方法进行了包裹)
Object.defineProperty(data,'count ",{get(){},set(){}})
存在问题:
新增属性、删除属性,界面不会更新
直接通过下标修改数组,界面不会自动更新
但是 vue2 给了解决方法,我们看以下代码:
<template> <div> <h3>我是vue2写的效果</h3> <h5 v-show="person.name">姓名:{{person.name}}</h5> <h5>年龄:{{person.age}}</h5> <h5 v-show="person.sex">性别:{{person.sex}}</h5> <h5>爱好:{{person.hobby}}</h5> <button @click="addSex">添加sex属性</button> <button @click="deleteName">删除name属性</button> <button @click="changeHobby">修改爱好</button> </div></template><script>import Vue from 'vue'export default { name: 'App', data(){ return{ person:{ name:'张三', age:18, hobby:['学习','吃饭'] } } }, methods:{ addSex(){ //这样直接加是不行的 //this.person.sex = '男' this.$set(this.person,"sex",'男') //Vue.set(this.person,"sex",'男') }, deleteName(){ //这样直接加是不行的 //delete this.person.name //this.$delete(this.person,'name') Vue.delete(this.person,"name") }, changeHobby(){ //这样直接加是不行的 //this.person.hobby[0] = '逛街' //可以这样 this.$set(this.person.hobby,0,'逛街') //或 //this.person.hobby.splice(0,1,"逛街") }, }}</script>
我们可以用 js 模拟 vue2 的响应式:
<script> //源数据 let person = { name:"张三", age:18 } let p = {} //模拟vue2实现响应式 Object.defineProperty(p,"name",{ configurable:true, get() {//有人读取name时调用 return person.name }, set(v) { person.name = v console.log("有人修改了name属性,我发现了,我要去更新界面"); } }) Object.defineProperty(p,"age",{ get() {//有人读取age时调用 return person.age }, set(v) { person.age = v console.log("有人修改了age属性,我发现了,我要去更新界面"); } })</script>
先输出 person,然后看下 p,当修改 name 或 age 时会检测到
它的问题是,如果增加一个 sex 属性,vue 不会检测到,虽然增加了 sex 属性,但它不像 name 和 age 有 getter 和 setter,不是响应式的
同样,当删除 name 属性时也监测不到
vue3的响应式
<template> <h2>一个人的信息</h2> <h4 v-show="person.name">姓名:{{ person.name }}</h4> <h4>年龄:{{ person.age }}</h4> <h4 v-show="person.sex">性别:{{ person.sex }}</h4>...... <button @click="changeInfo">修改人的信息</button> <button @click="addSex">添加一个sex属性</button> <button @click="deleteName">删除一个name属性</button></template><script>import {reactive} from 'vue'export default { name: 'App', setup() {...... function changeInfo() { ...... person.hobby[0] = '学习' } function addSex() { person.sex = "男" } function deleteName() { delete person.name } return { ...... addSex, deleteName } }}</script>
模拟 vue3 中的响应式:
<script> //源数据 let person = { name:"张三", age:18 } const p = new Proxy(person,{ //有人读取p的某个属性时调用 get(target, p, receiver) { console.log(`有人读取了p身上的${p}属性`); //return target[p] return Reflect.get(target,p) }, //有人修改、增加p的某个属性时调用 set(target, p, value, receiver) { console.log(`有人修改了p身上的${p},我要去更新界面了`); //target[p] = value Reflect.set(target,p,value) }, //有人删除p的某个属性时调用 deleteProperty(target, p) { console.log(`有人删除了p身上的${p},我要去更新界面了`); //return delete target[p] return Reflect.deleteProperty(target,p) } }) </script>
实现原理:
通过Proxy(代理)∶拦截对象中任意属性的变化,包括:属性值的读写、属性的添加、属性的删除等
通过Reflect(反射):对源对象的属性进行操作
MDN文档中描述的 Proxy 与 Reflect
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。Reflect不是一个函数对象,因此它是不可构造的。
new Proxy(data,{//拦截读取属性值get (target, prop){return Reflect.get(target,prop)},//拦截设置属性值或添加新属性set (target,prop, value) {return Reflect.set(target,prop, value)},//拦截删除属性deleteProperty (target,prop) {return Reflect.deleteProperty(target,prop)}})proxy.name = "tom"
“Vue3响应式原理实例分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!