目录
- 1. readonly与shallowReadonly函数
- 3. toRaw与markRaw函数
- 4. customRef函数
1. readonly与shallowReadonly函数
- readonly: 让一个响应式数据变为只读的(深只读)
- shallowReadonly:让一个响应式数据变为只读的(浅只读),可以修改第二层及更深的层数据
- 应用场景: 不希望数据被修改时。如别人提供的数据,我们只想使用,不想修改
使用示例:
<template><h2>当前x的值是:{{x}}</h2><button @click="x++">点我x++</button><h2>姓名:{{person.name}}</h2><h2>薪资:{{person.job.salary}}K</h2><button @click="person.name+='~'">修改姓名</button><button @click="person.job.salary++">涨薪</button>
</template><script>
import {ref,reactive,readonly,shallowReadonly} from 'vue'
export default {name: 'Student',setup(){let x = ref(0)let person = reactive({name:'张三',job:{salary:20}})x = readonly(x)person = shallowReadonly(person)return {x,person}}
}
</script>
效果如下:
- 点我x++,页面没反应
- 点击修改姓名,页面没反应
- 点击涨薪,页面上的薪资能正常变化
3. toRaw与markRaw函数
toRaw:
- 作用:将一个由reactive生成的响应式对象转为普通对象
- 注意:对这个普通对象的所有操作,会引起响应式对象的数据发生变化,但不会引起页面更新。等下一次页面被重新渲染时,发生改变的数据会更新到页面
markRaw:
- 作用:给一个响应式对象,添加一个对象类型的属性A。标记属性A,使其永远不会再成为响应式对象
- 注意:对属性A的所有操作,会引起属性A的数据发生变化,但不会引起页面更新。等下一次页面被重新渲染时,属性A发生改变的数据会更新到页面
- 应用场景:
- 有些值不应被设置为响应式的,例如引用的复杂的第三方类库等
- 当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能
使用示例:
Student.vue
<template><h2>人员全部信息: {{person}}</h2><h2>姓名:{{person.name}}</h2><button @click="person.name+='~'">修改姓名</button><br><button @click="getAndChangeRawPerson">先获取再改变最原始的person信息</button><br><button @click="addRawCar">给人添加一台最原始的车</button><br><button v-show="person.car" @click="changeCarPrice">改变车的价格</button>
</template><script>
import {reactive,toRaw,markRaw} from 'vue'
export default {name: 'Student',setup(){let person = reactive({name:'张三'})function getAndChangeRawPerson(){const rawPerson = toRaw(person)// 会引起person的数据变化,但页面不会刷新。页面会在下次渲染时更新改变的数据rawPerson.name+='$'}function addRawCar(){let car = {name:'大众',price:10}// 如果没有markRaw。person.car = car添加的是一个响应式数据。因为person是响应式的person.car = markRaw(car)}function changeCarPrice() {// 会引起person的数据变化,但页面不会刷新。页面会在下次渲染时更新改变的数据person.car.price = 99}return {person,getAndChangeRawPerson,addRawCar,changeCarPrice}}
}
</script>
效果如下:
-
点击先获取再改变最原始的person信息,页面没有发生变化,但其实person的数据已经改变了
-
再点击修改姓名,页面重新渲染,会将之前对toRaw数据的改变也更新到页面
-
点击给人添加一台最原始的车,页面能正常更新person。同时也会出现改变车的价格按钮
-
点击改变车的价格,页面没有发生变化,但其实person.car的数据已经改变了
-
再点击修改姓名,页面重新渲染,会将之前对markRaw的person.car的数据的改变也更新到页面
4. customRef函数
- 作用:创建一个自定义的ref,并对其读取track跟踪和更新trigger触发进行显式控制。
- 案例:实现防抖效果。如下所示:
App.vue
- 自定义一个ref。value就是ref管理的数据;delay是其它参数
- 读取value的值,会自动调用get。需要使用
track()
,通知Vue追踪value的变化,这样才会加载value更新后的数据 - 当修改value的值,会自动调用set,变传入需要修改的值。需要使用
trigger()
,通知Vue去重新解析模板 - set中创建了一个定时器。延迟一段时间,再去修改数据
- 使用
let keyWord = myRef('hello',500)
定义了一个响应式的数据keyWord,初始的数据是hello,每次修改keyword都会延迟500ms
<template><input type="text" v-model="keyWord"><h3>{{keyWord}}</h3>
</template><script>
import {customRef} from 'vue'
export default {name: 'App',setup() {// 自定义一个ref。value就是ref管理的数据;delay是其它参数function myRef(value, delay){let timerreturn customRef((track,trigger)=>{return {// 读取value的值,会自动调用getget(){console.log(`有人从myRef这个容器中读取数据了,我把${value}给他了`)track() // 通知Vue追踪value的变化,这样才会加载value更新后的数据return value},// 当修改value的值,会自动调用set,变传入需要修改的值set(newValue){console.log(`有人把myRef这个容器中数据改为了:${newValue}`)clearTimeout(timer) // 如果有定时器未执行,则先清除旧的定时器,防止抖动timer = setTimeout(()=>{ // 延迟一段时间,再去修改数据value = newValuetrigger() // 通知Vue去重新解析模板},delay)}}})}// 使用程自定义的reflet keyWord = myRef('hello',500)return {keyWord}}
}
</script>
效果如下:在输入框的hello后面,快速的输入123,过一段时间,下面的hello也更新为hello123