响应式对象toRef
使用toRef创建一个对象使其value子属性与源底层属性相互响应,如下:
<template>
<h1 v-text="state"></h1>
<h1 v-text="obj.name"></h1>
</template>
<script setup>
import { toRef } from 'vue';
let obj = {name:5, age:18}
let state = toRef(obj, 'name')
</script>
1、toRef函数的书写规范:toRef(参数1,"参数2")
- toRef 的 R 是大写
- 参数1是要绑定的父层。
- 参数2是要暴露的子属性的KEY,如是对象KEY是属性名用引号括起,如是数组KEY是索引号(数组KEY可以不用引号括起)。
2、toRef函数的内部原理
toRef会用ObjectRefImpl包装父层成一个对象。
- _object对象与父层全等
- _key属性定义要暴露的子属性
- value属性存储要暴露的值
- Prototype原型集,内含get value与set value函数,监测value值负责与父层的相互响应。
3、相互响应
- 父层相互响应: 新变量的_object对象与源父层全等,使用同一指针,引用同一对象,两者相互响应
- 父层失去响应:
当_object对象重新赋值为基本类型时(_object改用栈内存固定地址)两者失去响应,且value值为空;
当_object对象重新赋值一个新对象时(引用对象不同)两者失去响应,且value值为空,通过修改_key值重新定义要暴露的子属性,使value拥有新值。
当父层重新赋值为基本类型或赋值一个新对象时,两者失去响应,toRef的_object对象、_key等还是原值,依旧能照常使用。 - 子层响应: 通过get value与set value函数监测value值,value更新时,_object对象的_key值子属性同步更新,value与父层_key值子属性两者相互响应。
4、调用
暴露值包装在value属性里,因此调用值时需要对value解包。
逻辑部可以调用所有属性,模版部只能调用value属性。
逻辑部调用value属性: 需要加.value解包。
模版部调用: 如果是顶级属性自动解包(不需要加.value解包)、非顶级属性且不需计算会自动解包、非顶级属性需计算需要加value解包。
5、操作_object与_key
- 通过操作_object属性可操作父层。
通过操作_key属性可更改要暴露的子属性。
如下:<template> <h1 v-text="state"></h1> <h1 v-text="obj.name"></h1> <button @click="ee">测试_object</button> <button @click="ef">测试_key</button> </template> <script setup> import { toRef } from 'vue'; let obj = {name:5, age:18} let state = toRef(obj, 'name') function ee(){state._object.name='我通过_object改变',console.log(obj.name)} function ef(){state._key='age',console.log(state.value)} </script>
6、toRef与普通赋值的区别
- toRef只能赋值非底层属性
toRef只能赋值非底层属性,赋值后变量的_object对象与源父层同等。与普通赋值非底层属性一样拥有与源的相互响应性。toRef不能赋值底层属性,普通赋值能赋底层属性,新变量与源无相互响应性。 - toRef只暴露value子属
toRef只向DOM暴露value子属性以供DOM调用,普通赋值向DOM暴露所有子属性以供DOM调用。 伪赋值底层属性
toRef子属性value与父层下的底层属性相互响应,DOM调用value属性时不用加value解包,看上去就象底层属性赋值给toRef变量一样。他能做到普通赋值底层属性不能做到的与源相互响应。<template> <button @click="ee">测试引用型赋值响应</button> <button @click="ef">测试基本型赋值响应</button> <button @click="ed">测试toRef的子属性响应</button> </template> <script setup> import { toRef } from 'vue'; let obj = {name:{ttt:5, age:18}} let state = toRef(obj.name, 'ttt') let stat = obj.name let sta = obj.name.ttt function ee(){stat.ttt='引用型赋值响应1',console.log(obj.name),obj.name.ttt='引用型赋值响应2',console.log(stat)}// 有响应性 function ef(){sta='基本型赋值响应1',console.log(obj.name),obj.name.ttt='基本型赋值响应2',console.log(sta)}// 无响应性 function ed(){state.value='toRef的子属性响应1',console.log(obj.name),obj.name.ttt='toRef的子属性响应2',console.log(state)}// 有响应性 </script>
7、toRef专为响应性而生
不使用toRef赋值reactive的底层属性
新变量不继承Proxy代理包装,新变量与底层属性不相互响应,新变量不具DOM响应性。
使用toRef赋值reactive的底层属性
新变量会用ObjectRefImpl包装父层,父层继承Proxy代理,对外使用value子属性暴露这个底层属性,DOM调用value属性时不用加value解包,造成象toRef赋值reactive的底层属性的假象,新变量的value子属性与底层属性具有了相互响应,具有了DOM响应性。
(批量toRef)---toRefs
使用解构的方法,解构出的对象的子属性与源底层属性相互响应,如下:
<template>
<h1 v-text="name"></h1>
<h1 v-text="wowo"></h1>
<button @click="ee">我来改变</button>
</template>
<script setup>
import { reactive,toRefs } from 'vue';
let obj ={name:5,wowo:8}
let{name,wowo} = toRefs(obj)
function ee(){console.log(name,wowo)
obj.name={yy:88}}
</script>
1、toRefs函数的书写规范:{KEY1,KEY2}=toRefs(参数1)
toRefs 的 R 是大写
参数1是要绑定的父层。
遵循解构书写规范,解构对象型(新变量与源子属性同名且放在{}内),解构数组型(新变量可随意命名且放在[]内)。
2、toRefs函数的内部原理
解构出的每个变量都是用ObjectRefImpl包装的一个对象。
对象的_object子对象与父层全等
对象的_key子属性定义要暴露的子属性,value属性存储要暴露的值
Prototype原型集,内含get value与set value函数,监测value值负责与父层的相互响应。
3、相互响应
变量与源父层的相互响应性: 同toRef一样。
同构变量相互响应性: 因为他们都绑定同一个父层,通过操作_object可以改变其它同构变量值,更改_key值可以使自已成为其它同构变量,成为其他同构变量后与这个其它同构变量同等(拥有同样的_key值与value值)。如下:
<template>
<button @click="ee">改变对方</button>
<button @click="ef">成为对方</button>
<button @click="ed">成为对方</button>
</template>
<script setup>
import {toRefs } from 'vue';
let obj ={name:'我是name',wowo:'我是wowo'}
let {name,wowo}= toRefs(obj)
function gw(){obj.name='我是name',obj.wowo='我是wowo'}
function ee(){gw(),name._object.wowo='通过_object改变wowo',console.log(wowo.value) }
function ef(){gw(),name._key='wowo',console.log('通过_key,name成了',name.value) }
function ed(){gw(),name._key='wowo',name.value="name成了wowo后,可通过value改变wowo",console.log(wowo.value)}
</script>
4、调用
同toRef
5、toRefs专为响应性而生
不使用toRefs解构reactive的底层属性
解构出来的新变量不继承Proxy代理包装,新变量与赋值层不相互响应,不具DOM响应性。
使用toRefs解构reactive的底层属性
解构出来的新变量会用ObjectRefImpl包装父层并对外暴露这个底层属性,父层继承Proxy代理包装,新变量的value子属性与这个底层属性相互响应,并具有了DOM响应性。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。