[学习笔记] 动态组件扩展设计

166 阅读2分钟

本文基于抖音“哲玄前端”, 《全栈实践课》所写。

前言

  在日常工作中,80%的需求都可能来自于重复性极高的增删改查的基础操作。而该模型的动态组件就是为了结合原先定义的领域模型,从而减少这些重复性极高的需求,让开发者能够节省出大量时间专注新功能的开发。就此达到更加高效的开发以及避免重复中导致的基础错误发生,实现这个目标就需要提供高效的动态组件了。

模型以及动态组件参数提取

以下为模型中的定义,动态组件根据模型进行动态渲染

schemaConfig: {
  schema: {
    properties: {
      key: {
        // 实例
        createFormOption: {
           ...eleComponentConfig, // 标准 el-component 配置
           comType: '', // 控件类型 input/select/input-number
           visible: true, // 是否展示 (true/false),默认为true
           disabled: false, // 是否禁用 (true/false),默认为false
           default: '', // 默认值
           // comType === 'select' 时生效
           enumList: [] // 枚举列表
         },
      }
    }
  }
},
// 动态组件 相关配置
componentConfig: {
  // 实例
  createForm: {
    title: '', // 表单标题
    saveBtnText: '', // 保存按钮文案
  },
  // ...支持用户动态扩展
},

获取动态组件需要参数

const buildDtoSchema = (_schema, comName) => {
  if (!_schema?.properties) {
    return {};
  }
  
  const dtoSchema = {
    type: "object",
    properties: {},
  };

  // 提取有效 schema 字段信息
  for (const key in _schema.properties) {
    const props = _schema.properties[key];
    if (props[`${comName}Option`]) {
      let dtoProps = {};
      // 提取 props 中非 option 的部分,存放到 dtoProps 中
      for (const pKey in props) {
        if (pKey.indexOf("Option") < 0) {
          dtoProps[pKey] = props[pKey];
        }
      }
      // 处理 comName Option
      dtoProps = Object.assign({}, dtoProps, {
        option: props[`${comName}Option`],
      });

      // 处理 required 字段
      const { required } = _schema;
      if (required && required.find((pk) => pk === key)) {
        dtoProps.option.required = true;
      }

      dtoSchema.properties[key] = dtoProps;
    }
  }

  return dtoSchema;
};

动态组件封装

  个人总结的核心就是接收参数 实行功能 传递方法

<template>
  <el-drawer
    v-model="isShow"
    direction="rtl"
    :destroy-on-close="true"
    :size="550"
  >
    <template #header>
      <h3>{{title}}</h3>
    </template>
    <template #default>
      <schema-form
        ref="schemaFormRef"
        v-loading="loading"
        :schema="components[name]?.schema"
      ></schema-form>
    </template>
    <template #footer>
      <el-button
        type="primary"
        @click="save"
      >
        {{saveBtnText}}
      </el-button>
    </template>
  </el-drawer>
</template>
<script setup>
import { ref, inject } from "vue";
import { ElNotification } from "element-plus";
import $curl from "$elpisCommon/curl.js";
import SchemaForm from "$elpisWidgets/schema-form/schema-form.vue";

const { api, components } = inject("schemaViewData");

const emit = defineEmits(["command"]);

const name = ref("createForm");

const schemaFormRef = ref(null);
const isShow = ref(false);
const loading = ref(false);
const title = ref("");
const saveBtnText = ref("");

const show = () => {
  const { config } = components.value[name.value];

  title.value = config.title;
  saveBtnText.value = config.saveBtnText;

  isShow.value = true;
};

const close = () => {
  isShow.value = false;
};

const save = async () => {
  if (loading.value) {
    return;
  }

  if (!schemaFormRef.value.validate()) {
    return;
  }

  loading.value = true;
  const res = await $curl({
    method: "post",
    url: api.value,
    data: {
      ...schemaFormRef.value.getValue(),
    },
  });
  loading.value = false;

  if (!res || !res.success) {
    return;
  }

  ElNotification({
    title: "创建成功",
    message: "创建成功",
    type: "success",
  });

  close();

  emit("command", {
    event: "loadTableData",
  });
};

defineExpose({
  name,
  show,
});
</script>
<style lang="less" scoped>
</style>

总结

  通过模型规范化以及参数清除噪音配合动态组件,达到快速完成重复性工作从而提高工作效率。使得更多时间聚焦新功能开发跟性能优化上,从而做到完成工作的同时也能提升自我技能。