外观
外观
怡然
1412字约5分钟
2024-06-25
shallowRef
与 shallowReactive
shallowRef
a.value
,但不可以修改 a.value.b
。shallowReactive
通过使用
shallowRef()
和shallowReactive()
来绕开深度响应。浅层式API
创建的状态只在其顶层是响应式的,对所有深层的对象不会做任何处理,避免了对每一个内部属性做响应式所带来的性能成本,这使得属性的访问变得更快,可提升性能。
readonly
与 shallowReadonly
readonly
let original = reactive({ ... });
let sum1=ref(1)
let readOnlyCopy = readonly(original);
let sum2=readonly(sum1)
function changeSum(){
sum1.value+=1
sum2.value+=2 // sum2不可以修改,对象readOnlyCopy及其属性都不可以修改
}
shallowReadonly
let song=reactive({
name:'Because of You',
options:{
singer:'Kelly Clarkson',
album:'Breakaway'
}
})
let readonlySong = shallowReadonly(song)
function changeSong(){
readonlySong.name='同类' // 不可修改
readonlySong.options.singer='孙燕姿' // 可以修改
}
toRaw
与 markRaw
toRaw
toRaw
返回的对象不再是响应式的,不会触发视图更新。Vue
的库或外部系统时,使用 toRaw
可以确保它们收到的是普通对象。import { reactive,toRaw,markRaw,isReactive } from "vue";
/* toRaw */
// 响应式对象
let person = reactive({name:'tony',age:18})
// 原始对象
let rawPerson = toRaw(person)
markRaw
mockjs
时,为了防止误把mockjs
变为响应式对象,可以使用 markRaw
去标记mockjs
/* markRaw */
let citys = markRaw([
{id:'asdda01',name:'北京'},
{id:'asdda02',name:'上海'},
{id:'asdda03',name:'天津'},
{id:'asdda04',name:'重庆'}
])
// 根据原始对象citys去创建响应式对象citys2 —— 创建失败,因为citys被markRaw标记了
let citys2 = reactive(citys)
customRef
ref
,并对其依赖项跟踪和更新触发进行逻辑控制。 个人理解是将vue原本的响应式数据做了一次中间的拦截,在
get
读取数据时使用track()
跟踪数据之后,在set
中修改数据时可以做一些额外的操作,比如书写定时器进行防抖功能的实现,或是发送请求,做完这些操作时候再使用trigger()
触发数据的改变,使用customRef
定义的数据还是一个响应式数据,只不过在相应的同时还可以完成其他操作。在书写上和computed
的书写很像。
customRef
可以写在组件内部,处于复用的考虑写成了 hooks
)<template>
<h2>请输入搜索内容:{{ msg }}</h2>
<input type="text" v-model="msg">
</template>
<script setup lang="ts" name="Father">
import useMsgRef from './useMsgRef';
let { msg } = useMsgRef('将进酒', 1000)
</script>
import { customRef } from "vue";
export default function (initValue: string, delay: number) {
let timer: number;
let msg = customRef((track, trigger) => {
return {
get() {
track();
return initValue;
},
set(value) {
clearTimeout(timer);
timer = setTimeout(() => {
initValue = value;
trigger();
}, delay);
},
};
});
return { msg };
}
Teleport
teleport
标签包裹的内容可以插入到指定的容器内。<template>
<div class="app">
<h4>父组件</h4>
<img src="https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg" alt="">
<Child />
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './components/Child.vue';
</script>
<style scoped>
.app{
width:350px;
height: 200px;
background: #ccc;
border: 1px solid #aaa;
text-align: center;
filter: grayscale(100%); /**filter属性会影响容器内的fixed定位,导致相对于视窗的fixed定位不可用 */
}
img{
width: 100px;
}
</style>
<template>
<div class="child">
<button @click="showModa = true">显示弹窗</button>
<!--teleport标签上的to属性可以指定内部的HTML结构插入到指定位置,可以直接写标签,也可以写类名如.demo或者id如#demo-->
<teleport to="body">
<div class="modal" v-show="showModa">
<h5>将进酒</h5>
<p>李白</p>
<p>五花马千金裘,呼儿将出换美酒</p>
<button @click="showModa = false">关闭弹窗</button>
</div>
</teleport>
</div>
</template>
<script setup lang="ts" name="Child">
import { ref, reactive } from 'vue'
let showModa = ref(false)
</script>
<style scoped>
.child {
margin-top: 10px;
}
.modal {
width: 300px;
height: 200px;
background: #e8d4a7;
border: 1px solid #e3c06d;
position: fixed;
left: 50%;
margin-left: -150px;
top: 20px;
text-align: center;
}
</style>
Suspense
Suspense
包裹异步组件。import { defineAsyncComponent,Suspense } from "vue";
const Child = defineAsyncComponent(()=>import('./Child.vue')) // 异步引入组件
<template>
<div class="app">
<h3>我是App组件</h3>
<Suspense>
<template v-slot:default>
<!--异步组件加载完毕之后显示-->
<Child/>
</template>
<template v-slot:fallback>
<!--异步组件加载完毕之前显示的内容-->
<h3>加载中.......</h3>
</template>
</Suspense>
</div>
</template>