开发者可以使用 Vue 3 新提供的方法 ref 和 reactive 来定义响应式变量。
用 reactive 定义响应式对象或数组
reactive() 函数可以创建一个响应式对象或数组:
import { reactive } from 'vue'
const state = reactive({ count: 0 })
使用 reactive() 函数接收一个对象或者数组,然后返回一个 Proxy 实例(ES6新特性)。其行为表现与一般对象类似,不同的点在于 Vue 能够跟踪对响应式对象的访问与更改操作,包括增加或删除操作。
所以在 Vue 3 中使用 Proxy 代替了 Object.defineProperty()方法,实现了深层次的响应式,完善了 Vue 2 中出现的响应式bug。
其原理是通过 Proxy 实例拦截对源对象的访问和操作(数据劫持),再通过 Reflect 修改源对象的数据。
const person = {
name: '小明',
age: 18
}
// 使用 Proxy 创建一个 person 对象的代理对象
const p = new Proxy(person,{
// 有人读取了p对象的某个属性时调用
// target表示被代理的目标对象,propName表示被访问或操作的对象属性名
get(target, propName){
console.log(`有人读取了p对象上的${propName}属性`);
console.log("target",target);
return Reflect.get(target, propName)
},
// 有人修改了p对象的某个属性 或 追加了某个属性时调用
set(target, propName, value) {
console.log(`有人修改了p对象上的${propName}属性,我要去更新页面了`);
Reflect.set(target, propName, value);
},
// 有人删除了p对象的某个属性时调用
deleteProperty(target, propName) {
console.log(`有人删除了p对象上的${propName}属性,我要去更新页面了`);
return Reflect.deleteProperty(target, propName)
}
})
用 ref 定义响应式变量
由于 reactive 无法定义响应式的原始类型数据,于是可以使用 ref 定义任何类型的响应式数据。不过定义响应式对象或数组时 ref 函数还是会通过 reactive 函数创建一个Proxy实例。
ref 函数接收接收一个任何类型的参数,返回一个引用实现的实例对象,简称引用实例(RefImpl)。在该实例中有许多属性和方法,可是原始数据的值还是通过 value 属性获得和修改。
import { ref } from 'vue'
// ref 函数返回一个引用实例,值存储在value属性
let a = ref(0) // RefImpl {... , value: 0}
let person = ref({name: '小明', age: 18})
// RefImpl {... , value: Proxy {name: '小明', age: 18}}
// 修改数据
a.value++
person.value.name = '小美'
当 ref 在模板中作为顶层属性被访问时,它们会被自动“解包”,所以不需要使用 .value。
<template>
<h1>当前a的值为:{{a}}</h1>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
let a = ref(0)
return { a }
}
}
</script>
ref 函数的原理是通过 Object.defineProperty() 的 get 与 set 来实现响应式(数据劫持)