defineAsyncComponent 异步组件
defineAsyncComponent 旨在创建一个只有在需要时才会加载的异步组件(类似于懒加载)
参数
对于基本用法,defineAsyncComponent
可以接受一个返回 Promise
的工厂函数。Promise 的 resolve
回调应该在服务端返回组件定义后被调用。你也可以调用 reject(reason)
来表示加载失败。
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
app.component('async-component', AsyncComp)
当使用局部注册时,你也可以直接提供一个返回 Promise
的函数:
import { createApp, defineAsyncComponent } from 'vue'
createApp({
// ...
components: {
AsyncComponent: defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
}
})
对于高阶用法,defineAsyncComponent
可以接受一个对象:
defineAsyncComponent
方法还可以返回以下格式的对象:
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent({
// 工厂函数
loader: () => import('./Foo.vue')
// 加载异步组件时要使用的组件
loadingComponent: LoadingComponent,
// 加载失败时要使用的组件
errorComponent: ErrorComponent,
// 在显示 loadingComponent 之前的延迟 | 默认值:200(单位 ms)
delay: 200,
// 如果提供了 timeout ,并且加载组件的时间超过了设定值,将显示错误组件
// 默认值:Infinity(即永不超时,单位 ms)
timeout: 3000,
// 定义组件是否可挂起 | 默认值:true
suspensible: false,
/**
*
* @param {*} error 错误信息对象
* @param {*} retry 一个函数,用于指示当 promise 加载器 reject 时,加载器是否应该重试
* @param {*} fail 一个函数,指示加载程序结束退出
* @param {*} attempts 允许的最大重试次数
*/
onError(error, retry, fail, attempts) {
if (error.message.match(/fetch/) && attempts <= 3) {
// 请求发生错误时重试,最多可尝试 3 次
retry()
} else {
// 注意,retry/fail 就像 promise 的 resolve/reject 一样:
// 必须调用其中一个才能继续错误处理。
fail()
}
}
})
任何具有异步 setup 方法的组件都必须用来包装,如setup返回Promise
或者async
包装的,不管我们是否用defineAsyncComponent来异步加载,
即有时候我们需要请求后端的接口拿到数据才可以创建组件,也就是创建一个异步 setup 函数是业务需要,下面我们使用setTimeout()模拟API调用。
下面看下我们实际代码中的测试:
异步子组件 test3.vue
<template>
<div class="child">我是异步组件</div>
</template>
<script>
const getDataInfo = async () => {
// 异步请求
await new Promise(resolve => setTimeout(resolve, 1000));
const data = {
name: 'Ma Long',
address: '东京奥运'
};
return data;
};
export default {
async setup() {
const data = await getDataInfo();
return {
data
};
}
};
</script>
父组件 demo.vue
Suspense 不仅可以显示加载后的组件,还可以使用插槽fallback显示回退内容(加载中或者降级策略)。加载中显示fallback内容,直到子组件setup函数解析返回,再渲染子组件。 请注意,v-if在Suspense 这一级上。
<template>
<div style="color: red">
<button @click="show = true">Load</button>
<Suspense v-if="show">
<template #default>
<child />
</template>
<template #fallback>
<p>加载中</p>
</template>
</Suspense>
</div>
</template>
<script>
import Child from './test3.vue';
// 也可以采用下面的方式导入
// import { defineAsyncComponent } from 'vue';
// const LoginPopup = defineAsyncComponent(() => import('./test.vue'));
export default {
components: { Child },
data() {
return {
show: false
};
}
};
</script>
实现结果为:
1.点击Load按钮,开始加载child组件;
2.显示“加载中”
3.等child的setup异步返回后,显示出子组件。
其他详细内容可参考Vue3官网: vue3js.cn/docs/zh/api…
使用ref获取Dom节点内容
vue2中,ref主要的作用还是便于快速的获取dom元素或组件,因为ref操作相比document.getElementbyId会减少dom操作的节点消耗。
上一篇博文我们讲到了,ref用法1:使基本类型的数据响应
ref用法2:获取dom节点
错误示例:
<template>
<div class="container">
<img ref="imgRef" src="@/assets/images/dbTwo.png" />
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const imgRef = ref(null);
console.log('节点', imgRef.value);
return {
imgRef
};
}
};
</script>
控制台打印结果:
节点 null
上述问题的原因只要是在vue3的生命周期中,setup 相当于 vue2 的 beforeCreate
和created
,此时Dom还未完成创建和渲染,所以想要获取Dom节点必须要在onMounted
中取值;即满足以下三点:
1.声明在setup中;
2.使用在onMounted 中;
**3.必须return **
<template>
<div class="container">
<img ref="imgRef" src="@/assets/images/dbTwo.png" />
</div>
</template>
<script>
import { onMounted, ref } from 'vue';
export default {
setup() {
// 1.声明在setup中
const imgRef = ref(null);
onMounted(() => {
console.log('节点', imgRef.value); // 2.使用在onMounted 中
// 此处可以对获取到的dom做xxoo的事情,例如echarts的init等
});
return {
imgRef // 3.必须return 才可以
};
}
};
</script>