异步组件
在大型应用中,我们可能需要将应用分割成小一些的代码块 并且减少主包的体积(不需要在首屏加载得都可使用异步组件)
这时候就可以使用异步组件
顶层 await
在setup语法糖里面 使用方法
<script setup>
中可以使用顶层 await
。结果代码会被编译成 async setup()
<script setup>
const post = await fetch(`/api/post/1`).then(r => r.json())
</script>
父组件引用子组件 通过defineAsyncComponent加载异步配合import 函数模式便可以分包
<script setup lang="ts">
import { reactive, ref, markRaw, toRaw, defineAsyncComponent } from 'vue'
const Dialog = defineAsyncComponent(() => import('../../components/Dialog/index.vue'))
//完整写法
const AsyncComp = defineAsyncComponent({
// 加载函数
loader: () => import('./Foo.vue'),
// 加载异步组件时使用的组件
loadingComponent: LoadingComponent,
// 展示加载组件前的延迟时间,默认为 200ms
delay: 200,
// 加载失败后展示的组件
errorComponent: ErrorComponent,
// 如果提供了一个 timeout 时间限制,并超时了
// 也会显示这里配置的报错组件,默认值是:Infinity
timeout: 3000
})
内置组件suspense
<suspense>
组件有两个插槽。它们都只接收一个直接子节点。default
插槽里的节点会尽可能展示出来。如果不能,则展示 fallback
插槽里的节点。
<Suspense>
<template #default>
<Dialog>
<template #default>
<div>我在哪儿</div>
</template>
</Dialog>
</template>
<template #fallback>
<div>loading...</div>
</template>
</Suspense>
代码案例
父组件
<template>
<div class=""></div>
<suspense>
<template #default>
<Eleven></Eleven>
</template>
<template #fallback>
<div>loading.....也可使用骨架屏代替</div>
</template>
</suspense>
</template>
<script setup lang="ts">
import { ref, reactive, defineAsyncComponent } from "vue";
// import Eleven from "./components/eleven.vue";
const Eleven = defineAsyncComponent(
() => import("./components/eleven.vue")
);
</script>
<style lang="less" scoped></style>
eleven.vue
<template>
<div class="" v-for="(iten, index) in data" :key="index">
{{ iten?.name }}
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from "vue";
import { axiosXhr } from "./eleven_server";
let data = await axiosXhr("./data.json");
console.log(data);
</script>
<style lang="less" scoped></style>
eleven_server.ts
export const axiosXhr = (url: string) => {
return new Promise((resolve) => {
let xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onreadystatechange = () => {
console.log(xhr);
if (xhr.readyState === 4 && xhr.status === 200) {
setTimeout(() => {
resolve(JSON.parse(xhr.responseText));
}, 2000);
}
};
xhr.send();
});
};
data.json
[
{
"name": "cookie1"
},
{
"name": "cookie2"
}
]
效果图:
先加载fallback节点文本,2s后再加载匿名插槽节点
内置组件teleport
Teleport Vue 3.0新特性之一。
Teleport 是一种能够将我们的模板渲染至指定DOM节点,不受父级style、v-show等属性影响,但data、prop数据依旧能够共用的技术;类似于 React 的 Portal。
主要解决的问题 因为Teleport节点挂载在其他指定的DOM节点下,完全不受父级style样式影响
使用方法
通过to 属性 插入指定元素位置 to="body" 便可以将Teleport 内容传送到指定位置
<Teleport to="body">
<Loading></Loading>
</Teleport>
动态控制teleport
使用disabled 设置为 true则 to属性不生效 false 则生效
<teleport :disabled="true" to='body'>
<A></A>
</teleport>
代码案例
父组件:
<template>
<div class="parent">
<!--disabled 默认false -->
<teleport :disabled="false" to="body">
<Twelve></Twelve>
</teleport>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from "vue";
import Twelve from "./components/twelve.vue";
</script>
<style lang="less" scoped>
.parent {
width: 100vw;
height: 50vh;
background-color: pink;
position: relative; // 这样会改变弹窗的位置
}
</style>
子组件twelve.vue
<template>
<div class="dialog">弹窗</div>
</template>
<script setup lang="ts">
import { ref, reactive } from "vue";
</script>
<style lang="less" scoped>
.dialog {
width: 200px;
height: 200px;
background-color: black;
position: absolute;
left: 50%;
top: 50%;
}
</style>