系列文章目录
文章目录
shallowReactive
作用
只处理对象最外层属性的响应式(浅响应式)
什么时候用?
如果有一个对象数据,结构比较深,但变化时只是外层属性变化 ==> shallowReactive
实例
由于 salary 不是最外层的属性,所以当点击增加薪资时,薪资不会发生响应式变化
<template>
<div>
<h4>{
{
person}}</h4>
<h3>姓名:{
{
name}}</h3>
<h3>年龄:{
{
age}}</h3>
<h3>薪资:{
{
job.j1.salary}}K</h3>
<button @click="name+='~'">修改姓名</button>
<button @click="age++">增长年龄</button>
<button @click="job.j1.salary++">增加薪资</button>
</div>
</template>
<script>
import {
toRefs, shallowReactive } from "vue";
export default {
name: "Demo",
setup() {
// 数据
let person = shallowReactive({
name: '张三',
age: 18,
job: {
j1:{
salary: 20
}
}
})
// 返回一个对象
return {
person,
...toRefs(person)
};
},
};
</script>
点击姓名和年龄按钮都会响应式变化,点击薪资按钮不变化:
shallowRef
作用
只处理基本数据类型的响应式,不进行对象的响应式处理
什么时候用?
如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ==> shallowRef
实例
对于对象数据,不会修改该对象中的属性,所以点击按钮值不变
<template>
<div>
<h4>当前的x值是:{
{
x.y}}</h4>
<button @click="x.y++">点我x+1</button>
<hr>
</div>
</template>
<script>
import {
shallowRef } from "vue";
export default {
name: "Demo",
setup() {
// 数据
let x = shallowRef({
y: 0
})
//可以发现是object类型不是proxy,所以不能响应式变化
console.log(x);
// 返回一个对象
return {
x,
};
},
};
</script>
点击按钮,值不变:
控制台输出的 x(对象类型非Proxy类型,所以不能响应式):
若修改 button 里面的内容,生新的对象,此时改变的是 x,则会响应式变化
<button @click="x = {y:200}">点我更新x</button>
更新前:
更新后:
readonly
作用
让一个响应式数据变为只读的(深只读)
应用场景:不希望数据被修改时
实例
- 把 person 通过 readonly 变为只读的
- 点击按钮时不会发生任何响应式变化
<template>
<div>
<h3>姓名:{
{
name}}</h3>
<h3>年龄:{
{
age}}</h3>
<h3>薪资:{
{
job.j1.salary}}K</h3>
<button @click="name+='~'">修改姓名</button>
<button @click="age++">增长年龄</button>
<button @click="job.j1.salary++">增加薪资</button>
</div>
</template>
<script>
import {
reactive, toRefs, readonly } from "vue";
export default {
name: "Demo",
setup() {
// 数据
let person = reactive({
name: '张三',
age: 18,
job: {
j1:{
salary: 20
}
}
})
person = readonly(person)
// 返回一个对象
return {
...toRefs(person)
};
},
};
</script>
三个属性均为只读:
shallowReadonly
作用
让一个响应式数据变为只读的(浅只读)
应用场景:不希望数据被修改时
实例
- 浅只读,只是第一层限制只读
- 对深层的数据不影响其响应式
<template>
<div>
<h3>姓名:{
{
name}}</h3>
<h3>年龄:{
{
age}}</h3>
<h3>薪资:{
{
job.j1.salary}}K</h3>
<button @click="name+='~'">修改姓名</button>
<button @click="age++">增长年龄</button>
<button @click="job.j1.salary++">增加薪资</button>
</div>
</template>
<script>
import {
reactive, toRefs, shallowReadonly } from "vue";
export default {
name: "Demo",
setup() {
// 数据
let person = reactive({
name: '张三',
age: 18,
job: {
j1:{
salary: 20
}
}
})
person = shallowReadonly(person)
// 返回一个对象
return {
...toRefs(person)
};
},
};
</script>
name 和 age 为只读属性,薪资可以响应式变化:
toRaw
作用
将一个由 reactive 生成的响应式对象转为普通对象 (对 ref 无效)
使用场景
用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新
实例
通过
toRaw(xxx)
,可以将响应式对象转为普通对象
<template>
<div>
<h3>姓名:{
{
name}}</h3>
<h3>年龄:{
{
age}}</h3>
<h3>薪资:{
{
job.j1.salary}}K</h3>
<button @click="showRawPerson">输出最原始的person</button>
</div>
</template>
<script>
import {
reactive, toRefs, toRaw } from "vue";
export default {
name: "Demo",
setup() {
// 数据
let person = reactive({
name: '张三',
age: 18,
job: {
j1:{
salary: 20
}
}
})
function showRawPerson(){
const p = toRaw(person)
console.log(p);
}
// 返回一个对象
return {
...toRefs(person),
showRawPerson,
};
},
};
</script>
控制台输出原始数据:
markRaw
作用
标记一个对象,使其永远不会再成为响应式对象
应用场景
- 有些值不应被设置为响应式,例如复杂的第三方类库等
- 当渲染具有不可变数据的大列表时,跳过响应式转换可以提高性能
实例
使用
markRaw(xxx)
标记,则 xxx 不再是响应式对象
<template>
<div>
<h3>姓名:{
{
name}}</h3>
<h4 v-show="person.car">汽车信息:{
{
person.car}}</h4>
<button @click="addCar">给人添加一台车</button>
<button @click="person.car.name+='!'">换车名</button>
<button @click="person.car.price++">换价格</button>
</div>
</template>
<script>
import {
reactive, toRefs, markRaw } from "vue";
export default {
name: "Demo",
setup() {
// 数据
let person = reactive({
name: '张三',
})
function addCar(){
let car = {
name: '奔驰', price: '40'}
person.car = markRaw(car)
}
// 返回一个对象
return {
person,
...toRefs(person),
addCar
};
},
};
</script>
页面初始状态:
添加车后,点击换车名和换价格无变化:
customRef
作用
创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制
实例
- 首先要导入 customRef
- 定义自定义函数 — myRef
- 第一个 return 是把自己写的逻辑交出去,第二个 return 是语法规范要返回一个对象
myRef()
里的 value 是初始值,set()
里的 newValue 是新值set()
里面的trigger()
的作用是通知 Vue 去重新解析模板get()
里面的track()
的作用是通知 Vue 追踪 value 的变化(提前和 get 商量一下,让它认为这个 value 是有用的)- 声明一个 timer,在开启下一个定时器之前先清除定时器,是为了防抖。(防止快速输入时,输入框抖动的情况)
<template>
<div>
<input type="text" v-model="keyWord" />
<h3>{
{
keyWord }}</h3>
</div>
</template>
<script>
import {
customRef } from "vue";
export default {
name: "App",
setup() {
// 自定义ref —— 名为:myRef
function myRef(value, delay) {
let timer;
return customRef((track, trigger) => {
return {
get() {
console.log(`有人从myRef容器中读取数据了,我把${
value}给它了`);
track(); //通知Vue追踪value的变化(提前和get商量一下,让它认为这个value是有用的)
return value;
},
set(newValue) {
console.log(`有人把myRef容器中数据改了:${
newValue}`);
clearTimeout(timer)
timer = setTimeout(() => {
value = newValue;
trigger(); //通知Vue去重新解析模板
}, delay);
},
};
});
}
let keyWord = myRef("hello", 500);
return {
keyWord };
},
};
</script>
效果如下:
customRef
provide 与 inject
作用
实现祖与后代组件间通信
原理
父组件有一个 provide 选项来提供数据,后代组件有一个 inject 选项来开始使用这些数据
实例
App.vue(祖组件)
<template>
<div class="app">
<h3>我是App组件(祖),{
{
name }}——{
{
price }}</h3>
<Child />
</div>
</template>
<script>
import {
reactive, toRefs, provide } from "vue";
import Child from "./components/Child.vue";
export default {
name: "App",
components: {
Child },
setup() {
let car = reactive({
name: "奔驰", price: "40W" });
provide("car", car); //给自己的后代组件传递数据
return {
...toRefs(car) };
},
};
</script>
<style scoped>
.app {
background-color: gray;
padding: 10px;
}
</style>
Child.vue(子组件)
<template>
<div class="child">
<h3>我是Child组件(子)</h3>
<Son/>
</div>
</template>
<script>
import Son from './Son.vue';
export default {
name: "Child",
components: {
Son }
};
</script>
<style scoped>
.child {
background-color: skyblue;
padding: 10px;
}
</style>
Son.vue(孙组件)
<template>
<div class="son">
<h3>我是Son组件(孙),{
{
car.name}} —— {
{
car.price}}</h3>
</div>
</template>
<script>
import {
inject} from 'vue'
export default {
name: "Son",
setup(){
let car = inject('car')
return {
car}
}
};
</script>
<style scoped>
.son {
background-color: orange;
padding: 10px;
}
</style>
祖组件向孙组件传递数据:
响应式数据的判断
- isRef:检查一个值是否为一个ref对象
- isReactive:检查一个对象是否是由 reactive 创建的响应式代理
- isReadonly:检查一个对象是否是由 readonly 创建的只读代理
- isProxy:检查一个对象是否是由 reactive 或者 readonly 方法创建的代理
实例
对以上四种判断做测试:
<template>
<div class="app">
<h3>我是App组件</h3>
</div>
</template>
<script>
import {
ref, reactive, readonly, toRefs, isRef, isReactive, isReadonly, isProxy } from "vue";
export default {
name: "App",
setup() {
let car = reactive({
name: "奔驰", price: "40W" });
let sum = ref(0)
let car2 = readonly(car)
console.log(isRef(sum));
console.log(isReactive(car));
console.log(isReadonly(car2));
console.log(isProxy(car));
return {
sum, ...toRefs(car), car2 };
},
};
</script>
控制台输出结果:
不积跬步无以至千里 不积小流无以成江海
点个关注不迷路,持续更新中…