Vue3 Composition API下表单渲染时如何正确显示加载器?
Vue3 Composition API:Tab切换时表单渲染期间显示加载器的解决方案
你当前的代码中,nextTick()仅等待Vue完成当前DOM更新队列(即切换currentTab后显示对应的容器),但FormKit的表单渲染(尤其是包含大量字段时)是在DOM结构更新后进行的内部渲染过程,耗时3-4秒,导致loading状态过早被关闭,用户看不到加载效果。
以下是几种可行的解决方案:
方案一:利用FormKit的ready事件(推荐)
FormKit提供了@ready事件,当表单完成初始化和渲染后会触发,这是追踪表单渲染完成最准确的方式。
修改模板:
<template> <div> <p v-if="loading">Loading...</p> <TabView @tabChange="handleTabChange"> <TabPanel v-for="(tab, index) in tabs" :key="tab.id"> <template #header>{{ tab.label }}</template> <div v-if="currentTab === index"> <FormKit :data="tab.formData" @ready="() => onFormReady(tab.id)" /> </div> </TabPanel> </TabView> </div> </template>
修改脚本:
<script setup lang="ts"> import { ref, nextTick } from 'vue'; import TabView from './components/TabView.vue'; import TabPanel from './components/TabPanel.vue'; import FormKit from './components/FormKit.vue'; const tabs = ref([ { id: 1, label: 'Tab 1', formData: { /* 表单数据 */ } }, { id: 2, label: 'Tab 2', formData: { /* 表单数据 */ } }, ]); const loading = ref(false); const currentTab = ref(0); const handleTabChange = (index: number) => { loading.value = true; currentTab.value = index; }; const onFormReady = (tabId: number) => { // 仅关闭当前激活标签页的加载状态 const activeTab = tabs.value[currentTab.value]; if (activeTab.id === tabId) { nextTick().then(() => { loading.value = false; }); } }; </script>
方案二:监听DOM元素判断渲染完成(无组件事件时使用)
如果FormKit没有提供ready事件,可以通过监听表单容器的DOM元素,检查表单是否渲染完成:
修改模板:
<template> <div> <p v-if="loading">Loading...</p> <TabView @tabChange="handleTabChange"> <TabPanel v-for="(tab, index) in tabs" :key="index"> <template #header>{{ tab.label }}</template> <div v-if="currentTab === index" ref="formContainers" > <FormKit :data="tab.formData" /> </div> </TabPanel> </TabView> </div> </template>
修改脚本:
<script setup lang="ts"> import { ref, nextTick } from 'vue'; import TabView from './components/TabView.vue'; import TabPanel from './components/TabPanel.vue'; import FormKit from './components/FormKit.vue'; const tabs = ref([ { label: 'Tab 1', formData: { /* 表单数据 */ } }, { label: 'Tab 2', formData: { /* 表单数据 */ } }, ]); const loading = ref(false); const currentTab = ref(0); const formContainers = ref<HTMLElement[]>([]); const handleTabChange = async (index: number) => { loading.value = true; currentTab.value = index; await nextTick(); // 等待容器DOM生成 await waitForFormRender(); loading.value = false; }; const waitForFormRender = () => { return new Promise((resolve) => { const checkComplete = () => { const container = formContainers.value[currentTab.value]; if (!container) return resolve(null); // 根据FormKit实际生成的DOM结构调整选择器,比如检查是否存在表单字段 const hasRenderedFields = container.querySelectorAll('.formkit-field').length > 0; if (hasRenderedFields) { nextTick().then(resolve); } else { requestAnimationFrame(checkComplete); } }; requestAnimationFrame(checkComplete); }); }; </script>
方案三:兜底延迟方案(应急使用)
如果以上方法都无法实现,可以根据表单实际渲染时间设置固定延迟(不推荐,无法适配不同环境的渲染速度):
const handleTabChange = async (index: number) => { loading.value = true; currentTab.value = index; // 根据实际渲染时间调整延迟时长 await new Promise(resolve => setTimeout(resolve, 3500)); loading.value = false; };
内容的提问来源于stack exchange,提问作者Madhav mishra
相关产品推荐
相关产品推荐

