Vue3子组件渲染时未挂载问题寻求解决方案
解决嵌套动态组件仅挂载父组件的问题
1. 递归遍历组件树,确保全层级组件完成注册
当前代码仅处理了顶层组件,未递归遍历嵌套的children节点,导致子组件未被注册。需要修改注册逻辑,递归处理所有层级的组件:
// 递归注册所有层级的组件 function registerComponentTree(node) { // 从数据库获取当前组件的定义(这里假设node包含从数据库拿到的script/style/template) const scriptObj = JSON.parse(node.canvasDisplayScript); if (!scriptObj.methods) scriptObj.methods = {}; // 解析methods const methods = Object.entries(scriptObj.methods).reduce((acc, [key, value]) => { acc[key] = eval(`(${value})`); return acc; }, {}); // 生成标准化组件名 const componentName = `dynamic-${node.label.replace(/\s+/g, '-').toLowerCase()}`; componentDefinitions[node.label] = componentName; // 注册组件(Vue3需替换为app.component) Vue.component(componentName, { ...scriptObj, data() { return scriptObj.data ? scriptObj.data() : {}; }, mounted() { console.log(`Component '${componentName}' mounted`); const styleTag = document.createElement('style'); styleTag.innerHTML = node.canvasDisplayStyle; document.head.appendChild(styleTag); }, methods, template: node.canvasDisplayTemplate }); // 递归处理子组件 if (node.children?.length) { node.children.forEach(child => registerComponentTree(child)); } } // 启动注册流程 registerComponentTree(componentData);
2. 确保父组件模板正确引用子组件的注册名
父组件的模板必须使用注册后的标准化组件名(如dynamic-droppable-component),而非原始label(如Droppable Component)。如果数据库返回的模板用的是原始label,需提前替换:
// 替换模板中的原始label为注册后的组件名 function normalizeTemplate(template, definitions) { Object.entries(definitions).forEach(([label, name]) => { const tagName = label.replace(/\s+/g, '-').toLowerCase(); const regex = new RegExp(`<${tagName}>|<${tagName}\s+.*?>`, 'g'); template = template.replace(regex, match => match.replace(tagName, name)); }); return template; } // 注册组件时使用标准化后的模板 const normalizedTemplate = normalizeTemplate(node.canvasDisplayTemplate, componentDefinitions);
3. Vue3适配调整
如果使用Vue3,全局组件注册需通过app实例而非Vue.component:
const app = Vue.createApp({ /* 根组件配置 */ }); // 注册时替换为app.component app.component(componentName, { /* 组件选项 */ }); // 最后挂载根组件 app.mount('#app');
4. 替代方案:递归渲染动态组件
无需修改父组件模板,直接通过递归组件自动渲染嵌套结构:
<template> <component-renderer :node="componentData"></component-renderer> </template> <script> export default { components: { ComponentRenderer: { props: ['node'], template: ` <component :is="componentName"> <component-renderer v-for="child in node.children" :key="child.label" :node="child" ></component-renderer> </component> `, computed: { componentName() { return `dynamic-${this.node.label.replace(/\s+/g, '-').toLowerCase()}`; } } } }, data() { return { componentData: {/* 你的嵌套组件树 */} }; } }; </script>
内容的提问来源于stack exchange,提问作者Muhammad Zeerak
相关产品推荐
相关产品推荐

