Vue3 实战总结(二)

1,348 阅读3分钟

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 的 beforeCreatecreated,此时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>