【Vue3】响应性数据_1
readonly
& shallowReadonly
- 格式:
readonly(响应性数据)
readonly
修饰的数据,不可被修改
<template>
<p>obj.name: {{ obj.name }}</p>
<button @click="obj.name += '!'">修改 obj.name</button>
<hr />
<p>reObj.name: {{ reObj.name }}</p>
<!-- 点击不会被修改,控制台会抛出警告 -->
<button @click="reObj.name += '!'">修改 reObj.name</button>
</template>
<script>
import { reactive, readonly } from "vue";
export default {
name: "App",
setup() {
let obj = reactive({ name: "superman" });
let reObj = readonly(obj);
return { obj, reObj };
},
};
</script>
shallowReadonly
- 格式:
shallowReadonly(响应性数据)
shallowReadonly
修饰的数据,浅层数据不可被修改,但深层数据可以被修改
<template>
<!-- 浅层数据 -->
<p>obj.name: {{ obj.name }}</p>
<button @click="obj.name += '!'">修改 obj.name</button>
<p>reObj.name: {{ reObj.name }}</p>
<!-- 点击不会被修改,控制台会抛出警告 -->
<button @click="reObj.name += '!'">修改 reObj.name</button>
<hr />
<!-- 深层数据 -->
<p>obj.girlfriend.name: {{ obj.girlfriend.name }}</p>
<button @click="obj.girlfriend.name += '!'">
修改 obj.girlfriend.name
</button>
<p>reObj.girlfriend.name: {{ reObj.girlfriend.name }}</p>
<!-- 点击可以修改 -->
<button @click="reObj.girlfriend.name += '!'">
修改 reObj.girlfriend.name
</button>
</template>
<script>
import { reactive, shallowReadonly } from "@vue/reactivity";
export default {
name: "App",
setup() {
let obj = reactive({
name: "superman",
girlfriend: { name: "superwoman" },
});
let reObj = shallowReadonly(obj);
return { obj, reObj };
},
};
</script>
toRaw
& markRaw
- 将
reactive
修饰的响应式数据变为普通数据:toRaw(响应式数据)
- 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,都不会引起页面更新
<template>
<p>obj.name: {{ obj.name }}</p>
<button @click="obj.name += '!'">修改 obj.name</button>
<hr />
<p>raObj.name: {{ raObj.name }}</p>
<button @click="raObj.name += '!'">修改 raObj.name</button>
</template>
<script>
import { reactive, toRaw } from "@vue/reactivity";
export default {
name: "App",
setup() {
let obj = reactive({ name: "superman" });
let raObj = toRaw(obj);
return { obj, raObj };
},
};
</script>
可以发现,toRaw 修饰的数据,会变为普通数据,修改普通数据,页面不会重新渲染
但是数据是已经被改变了的,页面如果重新渲染的话,还是会显示最新数据
markRaw
- 用于标记一个对象数据,使其永远不能成为一个响应式数据
<template>
<p>obj: {{ obj }}</p>
<p>
第一步: 选择接收数据
<button @click="changeObj">changeObj</button> |
<button @click="maChangeObj">maChangeObj</button>
</p>
<p>
第二步: 选择改变的数据
<button @click="changeName">changeName</button> |
<button @click="changeGirl">changeGirl</button>
</p>
</template>
<script>
import { markRaw, reactive } from "vue";
export default {
name: "App",
setup() {
// 定义响应式数据
let obj = reactive({ name: "superman" });
// 假设通过 Ajax 接收一个对象数据
function changeObj() {
let girl = { name: "superwoman" };
obj.girlfriend = girl;
}
// 假设通过 Ajax 接收一个对象数据,并用 markRaw 修饰
function maChangeObj() {
let girl = markRaw({ name: "superwoman" });
obj.girlfriend = girl;
}
// 改变接收的数据
function changeGirl() { obj.girlfriend.name += "!" }
// 改变原数据
function changeName() { obj.name += "!" }
return {
obj,
changeObj,
changeGirl,
maChangeObj,
changeName,
};
},
};
</script>
可以发现,正常接收的对象数据,是可以被修改并渲染到页面上的;
但是,用 markRaw 修饰的对象数据,数据会被修改,但不会被渲染到页面上(当然,页面重新渲染时,还是会显示最新数据)
provide
& inject
provide
用于传递数据给后代组件:provide("XXX", 数据值)
inject
用于接收祖先组件传递的数据:inject("XXX")
<template>
<p>App: {{ obj }}</p>
<button @click="obj.name += '!'">修改数据 obj.name</button>
<hr />
<Son />
</template>
<script>
import { provide, reactive } from "vue";
import Son from "./components/Son.vue";
export default {
name: "App",
components: { Son },
setup() {
let obj = reactive({ name: "superman" });
provide("myObj", obj); // 传递数据
return { obj };
},
};
</script>
<template>
<p>Son: {{ msg }}</p>
<button @click="msg.name += '!'">修改数据</button>
</template>
<script>
import { inject } from "vue";
export default {
name: "Son",
setup() {
let msg = inject("myObj"); // 接收数据
return { msg };
},
};
</script>
此时,不论在哪个组件修改数据,数据都会被修改成功,并渲染到页面上
-
如果想后代组件无法修改并渲染数据,可以使用
toRaw
修饰数据:此时,后代组件无法修改并渲染接收的数据,但是数据是已经被修改了的,页面重新渲染的话,还是会显示最新数据
<template>
<p>App: {{ obj }}</p>
<button @click="obj.name += '!'">修改数据 obj.name</button>
<hr />
<Son />
</template>
<script>
import { provide, reactive, toRaw } from "vue";
import Son from "./components/Son.vue";
export default {
name: "App",
components: { Son },
setup() {
let obj = reactive({ name: "superman" });
let rawObj = toRaw(obj); // 将 reactive 修饰的响应式数据变为普通数据
provide("myObj", rawObj); // 传递数据
return { obj };
},
};
</script>
-
如果不允许修改数据,可以使用
readonly
修饰数据:此时,只有父级组件可以修改数据,后代组件不能修改接收的数据
<template>
<p>App: {{ obj }}</p>
<button @click="obj.name += '!'">修改数据 obj.name</button>
<hr />
<Son />
</template>
<script>
import { provide, reactive, readonly } from "vue";
import Son from "./components/Son.vue";
export default {
name: "App",
components: { Son },
setup() {
let obj = reactive({ name: "superman" });
let readObj = readonly(obj); // readonly 修饰的数据,不可被修改
provide("myObj", readObj); // 传递数据
return { obj };
},
};
</script>
判断响应式数据
isRef
- 检查一个值是否由ref
修饰isReactive
- 检查一个对象是否由reactive
修饰isReadonly
- 检查一个对象是否由readonly
修饰isProxy
- 检查一个对象是否由reactive
/readonly
修饰
<script>
import { isProxy, isReactive, isReadonly, isRef, reactive, readonly, ref } from 'vue';
export default {
name: "App",
setup() {
let person = reactive({ name: "superman" });
let num = ref(0);
let readonly_num = readonly(num);
console.log(isReactive(person)); // true
console.log(isRef(num)); // true
console.log(isReadonly(readonly_num)); // true
console.log(isProxy(readonly_num)); // true
},
};
</script>