toRef和toRefs的正确使用方式:
toRef
toRef(person, 'name') 是个ref对象,里面有value值,将这个value值利用getter指向了person源数据,所以toRef是引用,ref是复制。
操作后可以发现person中的源数据也是在同时变的
<template>
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<h2>job1薪资:{{salary}}</h2 -->
</template>
<script>
import { reactive, toRefs } from 'vue'
export default {
name: 'DemoPerson',
setup() {
let person = reactive({
name: '张珍',
age: 18,
job: {
j1: {
salary: 20
}
}
})
return {
person,
name: toRef(person, 'name'),
age: toRef(person, 'age'),
salary: toRef(person.job.j1, 'salary'),
}
}
}
</script>
<style>
</style>
toRefs
toRefs适合操作有很多数据的情况;如果很多数据用toRef,则要一个个去操作。
toRefs() 返回值是个对象,由于不能在一个对象中直接再放一个对象,所以需要用解构的方法将 toRefs() 返回的对象,全部摊开变成key-value;
<script>
import { reactive, toRefs } from 'vue'
export default {
name: 'DemoPerson',
setup() {
let person = reactive({
name: '张珍',
age: 18,
job: {
j1: {
salary: 20
}
}
})
return {
...toRefs(person)
}
}
}
</script>
<style>
</style>
对toRef() 及 toRefs() 的总结:
作用:创建一个 ref 对象,其value值指向另一个对象中的某个属性。
语法:const name = toRef(person,'name')
应用: 要将响应式对象中的某个属性单独提供给外部使用时。
扩展:toRefs 与 toRef 功能一致,但可以批量创建多个 ref 对象,
语法:toRefs(person)
接下来做一些其他的分析
我们在return数据时可能会觉得不用toRef()来操作,但是却发现是不可行的。
那就来分析一下,为什么不可行。
情况一:
为什么直接用person.xxx作为值赋给变量,却看不到数据的变化?
<template>
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<h2>job1薪资:{{salary}}</h2 -->
</template>
<script>
import { reactive, toRefs } from 'vue'
export default {
name: 'DemoPerson',
setup() {
let person = reactive({
name: '张珍',
age: 18,
job: {
j1: {
salary: 20
}
}
})
return {
name: person.name,
age: person.age,
salary: person.job.j1.salary,
}
</script>
分析:
let p = new Proxy(person, {
set(target, props, value) {
console.log(`${props}被修改了,更新!`)
Reflect.set(target, props, value)
}
})
// 通过p取出来name,交给了变量name
let name = p.name
我们到控制台:
1. 输入:p,得到结果:Proxy {name: '张珍', age: 18},是没问题的。
2. 再输入person,得到结果:{name: '张珍', age: 18},也是没问题的;
3. 再输入变量name,得到结果:'张珍', 仍然没问题;
我们再修改name,name = '李四' ,得到结果:'李四'
但是, 此时修改name = '李四',改的是name这个变量!
我们可以通过输入p和person来验证一下:
可以看到p和person中,name属性的值仍然是'张珍'。
这是什么原因呢?
name是自己新定义的一个变量:let name = p.name,这种方式就相当于直接写了 let name = '张珍',p.name就相当于一个字符串,然后给了name变量,是没有引用关系的。
就相当于:
let obj = { a: 100 }
let x = obj.a
x = 200
变量x确实会变成200, 但是obj中的a是不变的
所以:
name: person.name 中 person.name就是个字符串 相当于name: '张珍'
retrun {
name: person.name
}
return的内容就是返回了一个普通的对象!无法实现双向绑定
情况二:
为什么用ref,看到数据仍然可以变化,但是却不能直接用ref?
<template>
<h2>{{person}}</h2>
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<h2>job1薪资:{{salary}}</h2>
</template>
<script>
import { reactive, toRefs } from 'vue'
export default {
name: 'DemoPerson',
setup() {
let person = reactive({
name: '张珍',
age: 18,
job: {
j1: {
salary: 20
}
}
})
return {
person,
name: ref(person.name),
age: ref(person.age),
salary: ref(person.job.j1.salary)
}
}
}
</script>
<style>
</style>
这是什么原因呢?
用 ref(person.name) 读取出来的字符串'张珍',是打包成了一个新的ref,页面上读取的是新的ref的数据,但是实际上源数据person是没有变化的。
即:name: ref(person.name), // 虽然显示的是张珍~~
person, // 但是源数据person中name的值还是张珍,数据丝毫不变。