动态组件

43 阅读1分钟

🐨 前言

日常开发如果遇到一些重复增删改查的表单组件,比如创建 xxx 信息的表单、查看 xxx 信息的表单、修改 xxx 信息的表单,这个时候我们可以通过纯配置项和约定好的数据字段,去自动生成这些表单(UI + 交互 + 调接口)。

下面以创建表单组件 create-form 为例。

🐼 配置

总配置,包含所有可配置生成的动态组件。

componentConfig: {
    // create-form 表单相关配置
    createForm: {
        title: '',
        saveBtnText: ''
    }
}

某个数据字段在 createFormOption 中起到的作用/承担什么子组件

{
    key: {
        createFormOption: {
            ...eleComponentConfig,
            comType: '', // 该字段代表什么具体的组件
            visible: true,
            disabled: false,
            enumList: []
        }
    }
}

触发动态组件相关配置,比如点击某个按钮

buttons: [{
    eventKey: '', // 按钮事件名
    // 事件具体配置
    eventOption: {
         comName: '' // eventKey === 'showComponent' 时触发
    }
}]

🚀 实现

构造上面 componentConfig + createFormOption 为以下结构

 components = {
     createForm: {
         schema: {}, // 每个字段下的 createFormOption
         config: {} // 总配置 componentConfig - createForm
     }
 }

所有动态组件实际配置文件

const ComponentConfig = {
    createForm: {
        component: createForm // 实际组件
    }
}

引入动态组件

<components 
    :is="ComponentConfig[key]" 
    v-for="(item, key) in components" 
    :key="key"
    ref="comListRef"
/>

触发展示动态组件事件

const EventHandlerMap = {
    showComponent: // showComponent 展示动态组件
        function showComponent({ btnConfig, rowData }) {
          const { comName } = btnConfig.eventOption;
          if (!comName) {
            console.error(`没配置组件名`);
            return;
          }
          const comRef = comListRef.value.find((item) => item.name === comName);
          if (!comRef || typeof comRef.show !== 'function') {
            console.error(`找不到组件 ${comName}`);
            return;
          }
          comRef.show(rowData);
        }
}

createForm.vue,整个 createForm 组件

<el-drawer v-model="isShow" direction="rtl" :destroy-on-close="true" :size="550">
    <template #header>
      <h3>
        <!-- createForm.title -->
        {{ title }}
      </h3>
    </template>
    <template #default>
      <!-- 根据传入的字段,每个字段代表不同的表单组件,渲染展示即可-->
      <schema-form ref="schemaFormRef" v-loading="loading" :schema="components[name]?.schema" />
    </template>
    <template #footer>
      <el-button type="primary" @click="save">
         <!-- createForm.saveBtnText -->
        {{ saveBtnText }}
      </el-button>
    </template>
</el-drawer>