今天给大家分享几个很少人用,但是又非常有用的 Vue3 的 API,废话不多说,我们开始!
readonly
顾名思义,是只读的意思,如果你的数据被这个 API 包裹住的话,那么修改之后并不会触发响应式,并且会提示警告。
<template>
<div>{{ obj.age }}</div>
</template>
<script lang="ts" setup>
import { readonly, reactive } from 'vue';
let obj = reactive({
name: 'sunshine lin',
age: 20,
});
obj = readonly(obj);
obj.age = 18;
</script>
<style></style>
应用场景:readonly 的用途一般用于一些 hooks 暴露出来的变量,不想外界去修改,比如我封装一个 hooks,这样去做的话,那么外界只能用变量,但是不能修改变量,这样大大保护了 hooks 内部的逻辑
shallowRef
shallowRef 用来包住一个基础类型或者引用类型,如果是基础类型那么跟 ref 基本没区别,如果是引用类型的话,那么直接改深层属性是不能触发响应式的,除非直接修改引用地址,如下:
注意:改深层属性能改数据,只是没触发响应式,所以当下一次响应式触发的时候,你修改的深层数据会渲染到页面上。
应用场景:shallowRef 的用处主要用于一些比较大的但又变化不大的数据,比如我有一个表格数据,通过接口直接获取,并且主要用在前端展示,需要修改一些深层的属性,但是这些属性并不需要立即表现在页面上,比如以下例子,我只需要展示 name、age 字段,至于 isOld 字段并不需要展示,我想要计算 isOld 但是又不想触发响应式更新,所以可以用 shallowRef 包起来,进而减少响应式更新,优化性能。
import { onMounted, shallowRef } from 'vue';
interface IRow {
name: string;
age: 20;
isold?: boolean;
}
//hooks
export const useFetchData = () => {
const list = shallowRef<IRow[]>([]);
const fetchData = async () =>
//模拟请求
list.value = await new Promise<IRow[]>(resolve => {
resolve(
new Array(1000).map(() => ({
name: 'sunshine_lin',
age: 20,
})),
);
})
const checkIsold = ()=>{
list.value.forEach(({age },index)=>{
list.value[index].isold = age > 60;
});
};
onMounted(()=>{
fetchData();
});
return{
list,
checkIsold,
}
};
//页面中
//只需要展示name age
//不需要展示old
const columns = ['name','age'];
const {checkIsold,list } =useFetchData();
//判断成员是不是老人
checkIsold();
toRef & toRefs
1.toRef
在使用 reactive 的时候会有一个苦恼,那就是解构出来了 name 并放到模板里渲染,但是当我们想改原数据的时候,发现 name 并不会更新,一旦结构失去响应式。
<template>
<div class="about">
<div>{{ obj.name }}</div>
<div>{{ name }}</div>
</div>
</template>
<script lang="ts">
import { defineComponent, onBeforeMount, onMounted, reactive } from 'vue';
export default defineComponent({
name: 'about',
props: {},
components: {},
setup() {
const obj = reactive({
name:'wangHang',
age:'20'
});
let {name} = obj;//将obj对象的name属性的值解构出来,并赋给了一个名为name的变量
obj.name = 'wh123';
onBeforeMount(() => {})
onMounted(() => { })
return {
obj,
name
}
}
})
</script>
渲染结果:
这时我们可以使用 toRef,这个时候我们直接修改 name 也会触发原数据的修改,修改原数据也会触发 name 的修改。
<template>
<div class="about">
<div>{{ obj.name }}</div>
<div>{{ name }}</div>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRef } from 'vue';
export default defineComponent({
name: 'Home',
props: {},
components: {},
setup() {
const obj = reactive({
name:'wangHang',
age:'20'
});
const name = toRef(obj,'name');
//修改任何一个都会相互触发数据修改 (以下两个可单独)
obj.name = 'wh123';
name.value = 'wh456';
return {
obj,
name
}
}
})
</script>
渲染结果:
2.toRefs
但是如果是属性太多了,我们想一个一个去用 toRef 的话会写很多代码,所以我们可以使用 toRefs 一次性解构。
<template>
<div class="about">
<div>{{ name }}</div>
<div>{{ age }}</div>
<div>{{ hobbies }}</div>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRef, toRefs } from 'vue';
export default defineComponent({
name: 'toRefs',
setup() {
const obj = reactive({
name:'wangHang',
age:'20',
hobbies:['a']
});
const {name,age,hobbies} = toRefs(obj);
name.value = 'wh111';
age.value = '12';
hobbies.value = ['b'];
// let {hobbies} = obj;
return {
obj,
name,
age,
hobbies
}
}
})
</script>
toRaw & markRaw & unref
1.toRaw
toRaw 可以把一个响应式 reactive 转成普通对象,也就是把响应式对象转成非响应式对象
<template>
<div class="toRow">
<div>{{ rowObj.name }}</div>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, reactive, toRaw} from 'vue';
export default defineComponent({
name: 'toRow',
setup() {
const obj = reactive({
name:'wangHang',
age:'20'
});
let rowObj = toRaw(obj);
onMounted(()=>{
rowObj.name = 'wh';//不会触发视图更新
})
return {
obj,
rowObj
}
}
})
</script>
2.markRaw
markRaw
是一个用于标记对象的函数,它可以将一个对象标记为“非响应式”的,从而使其不会被Vue的响应式系统追踪和更新。具体来说,markRaw
函数接受一个对象作为参数,并返回一个与该对象相同的对象,但是该对象被标记为“非响应式”。
<template>
<div class="markRaw">
请看控制台输出内容
</div>
</template>
<script lang="ts">
import { defineComponent, markRaw, reactive } from 'vue';
export default defineComponent({
name: 'markRaw',
setup() {
const obj = reactive({
name: 'Tom',
age: 18
});
const rawObj = markRaw(obj);
console.log(rawObj.name); // 输出 'Tom'
rawObj.name = 'Jerry';
console.log(rawObj.name); // 输出 'Jerry'
console.log(obj.name); // 输出 'Tom'
return {
obj,
}
}
})
</script>
通过访问rawObj.name
,我们可以获取到obj
对象的name
属性的值。然而,当我们修改rawObj.name
的值时,obj.name
的值并没有发生变化,因为rawObj
被标记为“非响应式”,不会被Vue的响应式系统追踪和更新。
3.unref
unref 相当于返回 ref 的 value
<template>
<div class="unRef">
请看控制台输出内容
</div>
</template>
<script lang="ts">
import { defineComponent, ref, unref} from 'vue';
export default defineComponent({
name: 'unRef',
setup() {
const name = ref("wangHang");
console.log(name);
console.log(unref(name));//<==>console.log(name.value);
return {
name
}
}
})
</script>