在 Vue.js 3 中,使用 vue3-sfc-loader
可以动态加载异步的 Vue 单文件组件(.vue 文件)。这个工具允许你在运行时根据需要加载和解析 .vue 文件,使得组件的加载变得更加灵活和动态。
下面是一个简单的示例,演示如何使用 vue3-sfc-loader
动态加载一个异步的 Vue 组件:
安装依赖: 首先,需要安装 vue3-sfc-loader
和 @vue/compiler-sfc
(Vue 3 的单文件组件编译器)。
import { loadModule } from "vue3-sfc-loader";
开始加载时需要知道的事
defineAsyncComponent
是 Vue 3 提供的用于定义异步组件的函数
<template>
<div>
<component :is="previewComp"></component>
</div>
</template>
<component :is="previewComp"></component>
是动态组件,根据previewComp
的值来决定显示哪个组件。
import {
ref,
defineAsyncComponent,
shallowRef,
watch,
onMounted,
nextTick,
} from "vue";
import * as Vue from "vue";
import * as Cesium from "cesium";
import { loadModule } from "vue3-sfc-loader";
//映入你需要渲染的资源。包含js 在下面的代码中需要再次注册,
比如我们的vue下面仍然需要注册,第三方资源包也是如此
const init = (code: string) => {
try {
const options = {
moduleCache: {
vue: Vue,
cesium: Cesium,
},
async getFile() {
return code;
},
addStyle(textContent) {
const style = Object.assign(document.createElement("style"), {
textContent,
});
const ref = document.head.getElementsByTagName("style")[0] || null;
document.head.insertBefore(style, ref);
},
};
const comp = defineAsyncComponent(() =>
loadModule("myComponent.vue", options)
);
previewComp.value = comp;
} catch (err) {
console.error(err);
}
};
init
方法是初始化方法,根据传入的code
加载模块并设置到previewComp
。-
moduleCache
:这是一个对象,用来缓存模块。根据代码中的变量命名,它可能预先加载了一些模块,例如Vue
、FFCesium
、Cesium
、turf
和CesiumNavigation
。这些模块可以在加载myComponent.vue
组件时使用。 -
etFile()
函数:这是一个异步函数,返回值是传入的code
参数,即函数初始化时传入的字符串。 defineAsyncComponent()
是一个 Vue 3 提供的函数,用于定义异步组件。它接受一个函数作为参数,这个函数返回一个 Promise,用来加载和解析组件。loadModule("myComponent.vue", options)
调用loadModule
函数加载名为myComponent.vue
的 Vue 组件,并传入之前定义的options
对象作为配置。
就是这样拉。
然而我的示例里面previewComp是外面编辑器传进来的。展示一下源码
<template>
<div v-if="show" class="big">
<component :is="previewComp"></component>
</div>
</template>
<script setup lang="ts">
import {
ref,
defineAsyncComponent,
shallowRef,
watch,
onMounted,
nextTick,
} from "vue";
import * as Vue from "vue";
import * as Cesium from "cesium";
import { loadModule } from "vue3-sfc-loader";
import * as turf from "@turf/turf";
import * as CesiumNavigation from "cesium-navigation-es6"; //指南针插件
import FFCesium from "@/FFCesium/core/index.js";
let show = ref(false);
// import { particle } from "../cesium/resoure/index.ts";
const props = defineProps({
code: {
type: String,
required: true,
},
});
watch(
() => props.code,
(newValue, oldValue) => {
// 这里可以执行其他操作
console.log("监听");
init(newValue);
}
);
onMounted(() => {
// 初始化
show.value = true;
// 初始化
init(props.code);
});
const setCode = (code: string) => {
show.value = false;
// 重新渲染显示页,解决改错报错不再回归
console.log("yunx,shuoax");
nextTick(() => {
show.value = true;
// 在父组件里面再调用一次
init(code);
});
};
defineExpose({ setCode });
const previewComp = shallowRef();
const init = (code: string) => {
// console.log("FFCesium12", FFCesium);
try {
const options = {
moduleCache: {
vue: Vue,
FFCesium: FFCesium,
cesium: Cesium,
turf: turf,
CesiumNavigation: CesiumNavigation,
},
async getFile() {
return code;
},
addStyle(textContent) {
const style = Object.assign(document.createElement("style"), {
textContent,
});
const ref = document.head.getElementsByTagName("style")[0] || null;
document.head.insertBefore(style, ref);
},
};
const comp = defineAsyncComponent(() =>
loadModule("myComponent.vue", options)
);
previewComp.value = comp;
} catch (err) {
console.error(err);
}
};
// // 初始化
// init(props.code);
</script>
<style scoped>
.big {
width: 100%;
height: 100%;
}
</style>