在Vue的官方文档里是这么描述的
toRef():可以基于响应式对象上的一个属性,创建一个对应的 ref。这样创建的 ref 与其源属性保持同步:改变源属性的值将更新 ref 的值,反之亦然。
toRefs(): 将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref。每个单独的 ref 都是使用 [
toRef()
]创建的。
我们通过一个例子来了解怎么使用他们
<template>
<div>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改名字</button>
</div>
</template>
<script lang="ts" setup>
import {reactive} from 'vue'
let person = reactive({
name:'张三',
age:18
})
function changeName(){
person.name += 'X'
}
function changeAge(){
person.age += 1
}
</script>
<style scoped>
</style>
在这个例子中,我们用reactive代理了一个响应式的对象,这样一来name
和age
都变成响应式的数据了,并且点击对应的按钮会触发changeName
函数与changeAge
函数来修改他们的值
从person中解构出name与age
<template>
<div>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改名字</button>
</div>
</template>
<script lang="ts" setup>
import {reactive} from 'vue'
let person = reactive({
name:'张三',
age:18
})
let {name,age} = person
function changeName(){
name += 'X'
}
function changeAge(){
age += 1
}
</script>
<style scoped>
</style>
假设此时将person中的name和age解构出来,将函数中的person.name
和person.age
改成name
和age
,并且将{{ person.name }}
和{{ person.age }}
改成了{{ name }}
和{{ age }}
,那么此时还能实现之前的点击对应按钮改变name和age的效果吗?答案是不能的
因为此时通过let {name,age} = person
解构出来的name
和age
其实相当于我们let name = person.name
与let age = person.age
,虽然person.name
与person.age
是响应式的,但我们定义的name与age只接收第一次读到person.name与person.age的值,在函数中通过name += 'X'或age += 1时,其实只是在修改我们let出来的name与age的值,而他们并没有被我们代理成响应式的数据,所以在页面上展示时,他们是不会响应式变化的。
所以现在我们面临一个问题,我们从一个响应式的对象中解构出来的name与age他们并不是响应式的数据,那么如何把他们变成响应式的数据呢?
我们可以用toRefs()来帮我们解决这个问题
import{toRefs} from 'vue'
let {name,age} = toRefs(person)
此时我们解构出来的name 与 age 便成为响应式的了
我们在控制台打印出name与age可以看到此时name 与 age 是由ref定义的响应式数据
所以此时在函数中我们要加上.value
function changeName(){
name.value += 'X'
}
function changeAge(){
age.value += 1
}
所以toRefs()在这里的作用是把一个reactive所定义的对象变成一个一个由ref响应式数据所组成的对象
在控制台console.log(toRefs(person));
由于经过
toRefs(person)
处理后的person变成了一个一个由ref响应式数据所组成的对象,所以此时我们let {name,age} = toRefs(person)
得到的自然是响应式的name与age了
需要注意一个细节
toRefs()将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref。
在let {name,age} = toRefs(person)
中解构出来的name 与 age 是指向源对象相应属性的 ref,所以如果我们去修改name 与 age ,会同时修改person中原有的person.name与person.age
toRef()
既然toRefs()是把person变成了一个一个由ref响应式数据所组成的对象,那么toRef()的作用便是把person中单独的某个属性变成一个由ref代理的响应式数据
在这里我们将person里的age单独拎出来使其依然可以具有响应式的能力
let Age = toRef(person,'age')
console.log(Age);