假设有一个提交申请的入口页:
页面代码位于views/Home.vue
<template>
<div>
<div
style="
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
"
>
<h1>首页</h1>
<!-- // 用forms 数据渲染三个超链接 -->
<div v-for="form in forms" :key="form.key" style="margin: 10px 0">
<el-link @click="loadForm(form.key)" type="primary"></el-link>
</div>
</div>
</div>
</template>
<script>
import { ref } from "vue";
import { useRoute, useRouter } from "vue-router";
export default {
name: "Home",
components: {},
data() {
return {};
},
methods: {},
setup() {
const router = useRouter();
const forms = ref([
{ name: "采购申请", key: "BuyForm" },
{ name: "请假神", key: "HolidayForm" },
{ name: "出差申请", key: "TravelForm" },
]);
const loadForm = (formKey) => {
console.log(formKey);
router.push({ path: "/dynamicForm/" + formKey });
return;
};
return { forms, loadForm };
},
};
</script>
这里的申请链接点击后,会路由到/dynamicForm
这个带路径参数的地址。
路由定义:
import DynamicForm from '@/views/DynamicForm.vue'
// 定义路由规则
const routes = [
{ path: '/', component: HomeVue },
{ path: '/dynamicForm/:name', component: DynamicForm }
]
在DynamicForm.vue
中,获取路径参数,并且根据路径参数动态加载子组件:
<template>
<div class="button-container">
<el-button @click="goBack" type="primary" class="back-button"
>返回申请列表页</el-button
>
</div>
<div class="form-container">
<!-- 使用component is动态绑定异步组件 -->
<component :is="AsyncComp" v-if="AsyncComp && !isLoading" />
<!-- 添加加载状态提示 -->
<div v-else class="loading-text">表单加载中...</div>
</div>
</template>
<style scoped>
.button-container {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
</style>
<script>
import { useRoute, useRouter } from "vue-router";
import Formloading from "../components/Loading.vue";
import FormloadError from "../components/Error.vue";
import { ref, defineAsyncComponent, onMounted } from "vue";
export default {
name: "DynamicForm",
setup() {
const AsyncComp = ref(null);
// 从路由获取路径参数
const route = useRoute();
const router = useRouter();
const name = route.params.name;
const componentPath = `../components/form/${name}.vue`;
const isLoading = ref(true);
// 定义异步组件
AsyncComp.value = defineAsyncComponent({
loader: () => import(componentPath),
loadingComponent: Formloading,
errorComponent: FormloadError,
delay: 200,
timeout: 3000,
});
const goBack = () => {
router.push({ path: "/" });
};
onMounted(() => {
isLoading.value = false;
});
return { AsyncComp, goBack, isLoading };
},
};
</script>
这里的Formloading
和FormloadError
是加载中和加载失败时展示的备选组件。
不同的申请单位于components/form/xxx.vue
。
需要注意的是,在使用 defineAsyncComponent
方法异步加载子组件时,import
方法接收的需要动态加载的组件路径只能是相对路径,比如./xxx
或../xxx
这样。如果路径是@/components/...
这样,会报错,错误信息显示找不到对应的页面。
在上面这个示例中,这样动态加载子组件显得不是那么必要。完全可以使用import xxx from xxx
加载所有的子组件,然后按照需要使用。但如果子组件过多,这样会有不必要的性能消耗,此外,如果申请单有迭代需求,比如有多个版本(v1,v2,v3等等),可以通过服务端配置来决定当前使用的是哪个申请单组件。
除了这种方式外,更灵活的是将 vue 源码放在服务端(比如数据库),页面加载时从服务端获取并加载,可以看作是“真动态加载”,但那样需要使用 vue 的编译器,将 vue 源码编译为 js 和 html,然后加载。步骤繁琐且容易遇到各种技术问题,且可能会带来安全隐患。
本文的完整示例代码可以从获取。
文章评论