Vue3响应式原理实例分析

蜗牛 互联网技术资讯 2022-06-15 26 0

本篇内容介绍了“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 时会检测到

Vue3响应式原理实例分析  vue3 第1张

它的问题是,如果增加一个 sex 属性,vue 不会检测到,虽然增加了 sex 属性,但它不像 name 和 age 有 getter 和 setter,不是响应式的

Vue3响应式原理实例分析  vue3 第2张

同样,当删除 name 属性时也监测不到

Vue3响应式原理实例分析  vue3 第3张

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>

Vue3响应式原理实例分析  vue3 第4张

Vue3响应式原理实例分析  vue3 第5张

实现原理:

  • 通过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响应式原理实例分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注蜗牛博客网站,小编将为大家输出更多高质量的实用文章!

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:niceseo99@gmail.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

评论