需求描述:
实现一个自定义图表拖拽功能,拖拽的组件中有下拉框,输入框,时间选择器等组件。为了方便,决定使用Element UI组件。
问题描述:
通过拖拽创建一个div元素(父元素),通过vue的方法defineAsyncComponent引入一个异步组件,使用createApp创建一个vue实例,并将其挂载到父元素上。部分代码如下
import { createApp, defineAsyncComponent } from "vue";
function createInputCom(data) {
let oldVue = null;
oldVue = defineAsyncComponent(() => import("../components/viewComp/input.vue"));
let baseComp = document.querySelector("#" + data.id);
baseComp.style.padding = "10px 20px"
let Id = data.id;
this.id = Id;
let obj = {
id: Id,
type: 'type_label',
};
this.option = obj;
this.baseVue = createApp(oldVue, obj).use(ElementPlus, { locale });
this.baseVue.config.globalProperties =
window.globalApp._context.config.globalProperties;
this.baseVue.mount(baseComp);
this.registerComponentInWindow(Id, this.baseVue, data.ElConfig)
}
input.vue
<template>
<div class="input-box">
<el-input v-model="value" placeholder="请输入" />
</div>
</template>
<script>
import { getCurrentInstance, onMounted, ref, watch } from "vue";
import { useInstanceContent } from "../../utils/combinedFunction.js"
export default {
setup() {
const { proxy } = getCurrentInstance();
const value = ref("");
const changeInputValue = (val) => {
value.value = val
}
onMounted(() => {
useInstanceContent(proxy.$attrs.id, proxy)
});
return {
value,
changeInputValue,
};
},
};
</script>
<style scoped>
.input-box {
width: 100%;
height: 100%;
}
</style>
因为会通过外在编辑对组件的内容进行修改,所以想要通过vue实例去获取到内部组件(这里指input.vue)的实例。这里通过对this.baseVae进行查看,发现 this.baseVae_instance.vnode.el.__vueParentComponent.ctx可以访问到内部组件的实例(目标实例)
找到实例,将目标实例挂载到全局上以便进行使用。
function registerComponentInWindow(ID, content, config) {
Object.prototype.toString.call(window.components) !== '[object Object]' ? window.components = {} : ''
setTimeout(() => {
if (content._instance.vnode.el.__vueParentComponent && content._instance.vnode.el.__vueParentComponent.ctx) {
window.components[ID] = {
content: content._instance.vnode.el.__vueParentComponent.ctx,
config: {
labelCom: {},
selectCom: {},
inputCom: {},
buttonCom: {},
dateCom: {},
tableCom: {},
}, // 存放一些需要的属性
}
}
}, 500) // 这里需要异步,不然取不到this.baseVue的实例。
}
这种方法在本地开发中是没有问题,但是在打包发布之后这个方法就有问题了,打包发布之后的this.baseVae_instance值为null,就导致其它地方没法操作我们的组件。
原因
目前还不知道,知道的老师可以在评论区留下知识,谢谢。
解决方案
在每个组件的mounted阶段,进行全局注册
export function useInstanceContent (id, content) {
Object.prototype.toString.call(window.components) !== '[object Object]' ? window.components = {} : ''
Object.prototype.toString.call(window.components[id]) !== '[object Object]' ? window.components[id] = {
content: {},
config: {}
} : ''
window.components[id].content = content
}