本文主要介绍以下api
readonly()、isReadonly()、shallowReadonly()、isProxy()、toRaw()、markRaw()
1、readonly()
接受一个对象 (不论是响应式还是普通的) 或是一个 ref,返回一个原值的只读代理
只读代理是深层的:对任何嵌套属性的访问都将是只读的。它的 ref 解包行为与 reactive() 相同,但解包得到的值是只读的。
要避免深层级的转换行为,请使用 shallowReadonly() 作替代。
注意:readonly函数只能将一个对象转换为只读对象,而不能将一个数组或Map等其他类型的数据结构转换为只读对象
csharp
<script setup>
let person = reactive({
job: '搬砖',
love: '象棋'
})
const readObj = readonly(person)
const handleChangeJOb = () => {
// person.job = '躺平' // 源代理对象person依然是响应式对象,可以进行更改
readObj.job = '搬不动了' // 代理对象readObj是只读对象,不能进行更改
// 但是 如何同时修改源代理对象 person 和只读对象readObj 的相同属性 job时,依然可以触发视图中 readObj.job的视图进行更新
如果强制修改只读属性,会报错
}
</script>
2、shallowReadonly()
shallowReadonly()同readonly()一样都是将一个对象转换为只读对象,但是shallowReadonly()不会对嵌套对象进行转换,只会对最外层对象进行转换,即只能将根级别属性转换为只读,而深层嵌套的属性,依然原样存储保留,原来的响应式;
csharp
<script setup>
let person = reactive({
job: '搬砖',
love: '象棋',
others: {
name: '张三',
age: 18
}
})
// 转换为浅层只读对象
const shallRed = shallowReadonly(person)
// shallRed.love = '跑步' // shallowReadonly创建的对象shallRed是浅读对象,根级别属性,love不能进行修改,修改时候会报错
shallRed.others.name = `${shallRed.others.name}+$` // 而是 // shallowReadonly创建的对象shallRed是浅读对象,深层级别属性,others.name可以进行修改,可以触发视图更新
</script>
3、isReadonly()
校验传入的对象是否为只读对象,返回一个布尔值;比如使用readonly() 和 shallowReadonly() 创建的对象,都可以通过isReadonly()进行校验,校验而获取 ture
csharp
<script setup>
let shallObj = shallowReadonly({
job: '搬砖',
love: '象棋',
others: {
name: '张三',
age: 18
}
})
const isShall = isReadonly(shallObj) // true
</script>
4、isProxy()
校验传入的对象是否为代理对象,返回一个布尔值;比如使用reactive()、shallowReactive()、 readonly()、shallowReadonly() 创建的对象,都可以通过isProxy()进行校验,校验而获取 ture
注意:只有针对vue3 创建的响应式对象才会返回true;如果使用new Proxy()创建的对象,isProxy()返回false;
csharp
<script setup>
let person = reactive({
job: '搬砖',
love: '象棋',
others: {
name: '张三',
age: 18
}
})
const isPerson = isProxy(person) // true
// 自定义代理对象,详细描述请查看 MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
let person2 = new Proxy({}, {
get(target, key, receiver) {
retrun Reflect.get(target, key, receiver) || target[key]
},
set(target, key, value, receiver) {
return Reflect.set(target, key, value, receiver) || target[key] = value
}
})
const isPerson2 = isProxy(person2) // false
</script>
5、toRaw()
将一个代理对象转换为原值,返回一个原值;即不会更新UI视图
应用场景:比如,ref/reactive 创建的响应式数据类型每次修改都会被追踪,都会更新UI界面,但是这样是非常消耗性能的,假如我们有一些操作不需要追踪,不需要更新UI界面,那么这个时候我们就可以通过toRaw方法拿到它的原始数据,对原始数据进行修改,这样就不会被追踪,这样就不会更新UI界面,这样性能就好了。
csharp
<template>
<br>
pObj:{{ pObj }}
<br>
rawObj:{{ pObj }}
<br>
<button @click="handleChangePobj">Pobj</button>
</template>
<script setup>
import { reactive, toRaw } from 'vue'
const baseObj = {
name: 'Andy',
age: 18,
job: '梦想躺平'
}
let pObj = reactive(baseObj)
let rawObj = toRaw(baseObj)
const handleChangePobj = () => {
rawObj.name = '王五'
console.log('=rawObj==', rawObj) // 单独操作rawObj.name时; 更改了原始对象,值发生了改变,但是视图不会更新
console.log('=pObj==', pObj) // 会发现操作rawObj.name时,pObj.name并没有更新,因为pObj是reactive创建的响应式对象,但是rawObj是toRaw创建的原始对象,所以pObj.name,值发是勒改变,但是视图并没有更新
}
</script>
6、markRaw()
讲一个对象标记为不可转化为响应式代理对象,并且返回对象本身
markRaw() 与 toRaw() 互为对应,markRaw() 会将一个对象标记为不可转化为响应式代理对象,并且返回对象本身;
比如:
1.在一些第三方库引用中,第三方的库是不需要响应式的;
2.当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能
3.在动态渲染组件的时候我们就可以使用 markRaw 包裹。
csharp
<script setup>
import { reactive, markRaw } from 'vue'
const baseObj = {
name: 'Andy',
age: 18,
job: '梦想躺平'
}
let pObj = reactive(baseObj)
let rawObj = markRaw(baseObj)
const handleChangePobj = () => {
rawObj.name = '王五'
console.log('=rawObj==', rawObj) // 单独操作rawObj.name,发现视图是不会更新的;因为markRaw() 创建的是非响应式的对象;
}
let pObj2 = reactive({
name: 'Andy',
age: 18,
job: '梦想躺平'
})
pObj2['otherJob'] = markRaw({otherJob: '搬砖'}) // 此时pObj2['otherJob'] 会变成非响应式对象,不会被追踪,不会更新视图,而其他属性依然是响应式的;
</script>