vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue3响应式

一文详解Vue3响应式原理

作者:​ 奔跑吧鸡翅   ​

这篇文章主要介绍了一文详解Vue3响应式原理,文章通过与vue2.x 的响应式做对比详解展现出了Vue3响应式原理详情,感兴趣的小伙伴可以参考一下

回顾 vue2.x 的响应式

实现原理:

Object.defineProperty(data,'count ",{
	get(){},
	set(){}
})

存在问题:

但是 vue2 给了解决方法,我们看以下代码:

<template>
  <div>
    <h2>我是vue2写的效果</h2>
    <h4 v-show="person.name">姓名:{{person.name}}</h4>
    <h4>年龄:{{person.age}}</h4>
    <h4 v-show="person.sex">性别:{{person.sex}}</h4>
    <h4>爱好:{{person.hobby}}</h4>
    <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>
  <h1>一个人的信息</h1>
  <h3 v-show="person.name">姓名:{{ person.name }}</h3>
  <h3>年龄:{{ person.age }}</h3>
  <h3 v-show="person.sex">性别:{{ person.sex }}</h3>
	......
  <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>

实现原理:

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响应式原理的文章就介绍到这了,更多相关Vue3响应式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文