[设计器 vjdesign] 简化配置 element 表单

1,221 阅读1分钟

jformer 是一个动态表单呈现组件,只需要传递 json 数据就可以显示出界面和功能, 这篇文章 实现了一个渲染处理简化element表单配置,现在实现通过 vjdesign 可视化设计器编辑表单

vjdesign 是一个 vue 界面可视化设计器,通过配置就可实现增加支持的组件和组件的属性

效果演示

完整示例

html 页

首先实现一个html页,读取 profile.json 配置文件实现支持element组件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Static Template</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script src="https://cdn.jsdelivr.net/npm/vjdesign"></script>
    <script src="https://cdn.jsdelivr.net/npm/element-ui/lib/index.js"></script>
    <script src="./element-ext.js"></script>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/vjdesign/dist/vjdesign.css"
    />
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/element-ui/lib/theme-chalk/index.css"
    />
    <style>
      html {
        font-size: 14px;
      }

      #app {
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <v-jdesign v-model="config" v-bind:profile="profile"></v-jdesign>
    </div>
    <script>
      new Vue({
        data() {
          return { config: {}, profile: {} };
        },
        async mounted() {
          const response = await fetch("./profile.json");
          this.profile = await response.json();
        }
      }).$mount("#app");
    </script>
  </body>
</html>

provider 扩展实现

这里增加一个 colProps 属性来实现在表单组件外套一个 el-col 实现整体设置列宽

// 实现一个渲染处理 provider 实现在组件上定义 elForm
// 就可以自动在组件外层加上 el-form-item
const elementFormProps = (field) => {
  if (!field.elForm) {
    return;
  }

  // 复制组件原始配置
  const originField = { ...field };

  // 将组件名改成 el-form-item
  field.component = "el-form-item";

  // 将原组件的复制赋给组件下级实现改变界面结构
  field.children = [originField];

  // 将 elForm 属性作为 el-form-item 的属性
  field.fieldOptions = {
    props: field.elForm
  };

  // 如果组件关联了数据属性则将数据属性作为 el-form-item 的数据属性
  if (originField.model) {
    field.fieldOptions.props.prop = Array.isArray(originField.model)
      ? originField.model[0]
      : originField.model;
  }

  // 删除 elForm 定义避免下级组件渲染处理时无限循环
  delete field.elForm;
  delete originField.elForm;
  delete originField.colProps;
};

// 实现一个渲染处理 provider 实现在组件上定义 colProps 相关属性
// 就可以自动在组件外层加上 el-col
const colProps = (field) => {
  if (!field.colProps) {
    return;
  }

  const originField = { ...field };
  field.component = "el-col";
  field.children = [originField];
  field.fieldOptions = {
    props: field.colProps
  };

  delete field.colProps;
  delete originField.colProps;
};

// 将定义的 provider 应用于 jformer
window.vjdesign.default.form.use(({ provider }) => {
  // 分别注册 el-form-item 和 el-col 支持
  provider(elementFormProps).withIndex(1);
  provider(colProps).withIndex(2);
});

配置文件

{
  "components": [
    {
      "name": "el-row",
      "label": "行",
      "group": "ElementUI",
      "designer": "classContainer",
      "properties": [
        {
          "name": "fieldOptions.props.gutter",
          "label": "间隔",
          "group": "组件",
          "editor": "number"
        }
      ]
    },
    {
      "name": "el-form",
      "label": "表单",
      "group": "ElementUI",
      "designer": "container",
      "properties": [
        {
          "name": "fieldOptions.props.model",
          "label": "表单数据",
          "group": "数据"
        },
        {
          "name": "fieldOptions.props.labelWidth",
          "label": "前缀宽度",
          "group": "组件"
        }
      ]
    },
    {
      "name": "el-input",
      "label": "输入框",
      "group": "ElementUI",
      "properties": ["model", "elForm.label", "elForm.rules", "colProps.span"]
    },
    {
      "name": "el-select",
      "label": "选择框",
      "group": "ElementUI",
      "properties": ["model", "elForm.label", "elForm.rules", "colProps.span"]
    }
  ],
  "properties": [
    { "name": "elForm.label", "label": "前缀", "group": "表单" },
    {
      "name": "elForm.rules",
      "label": "验证规则",
      "group": "表单",
      "properties": [
        {
          "name": "type",
          "label": "类型",
          "transform": false,
          "editor": {
            "name": "select",
            "options": {
              "items": [
                { "value": "string", "label": "字符串" },
                { "value": "number", "label": "数字" },
                { "value": "boolean", "label": "布尔" },
                { "value": "array", "label": "数组" }
              ]
            }
          }
        },
        { "name": "required", "label": "是否必填", "editor": "switch" },
        { "name": "message", "label": "错误提示" },
        { "name": "min", "label": "最小值", "editor": "number" },
        { "name": "max", "label": "最大值", "editor": "number" },
        { "name": "pattern", "label": "正则" }
      ],
      "editor": "array"
    },
    {
      "name": "colProps.span",
      "label": "列宽",
      "group": "布局",
      "editor": "number"
    }
  ]
}

界面呈现

vjdesign 的 v-model 输出结果就是表单的配置,将配置赋给 jformer 相关属性就可呈现表单

<v-jdesign v-model="config" v-bind:profile="profile"></v-jdesign>

jformer 呈现方法如下,config.json 就是 vjdesign 的 v-model 输出结果

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Static Template</title>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script src="https://cdn.jsdelivr.net/npm/jformer"></script>
    <script src="https://cdn.jsdelivr.net/npm/element-ui/lib/index.js"></script>
    <!-- 记得引用 provider 的实现 -->
    <script src="./element-ext.js"></script>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/element-ui/lib/theme-chalk/index.css"
    />
  </head>
  <body>
    <div id="app">
      <j-former v-bind:config="config"></j-former>
    </div>
    <script>
      new Vue({
        data() {
          return {
            config: {}
          };
        },
        async mounted() {
          // 读取 config
          const response = await fetch("./config.json");
          this.config = await response.json();
        }
      }).$mount("#app");
    </script>
  </body>
</html>

注意

还要记得将 provider 扩展实现 element-ext.js 也引用进来,让 jformer 呈现时支持 elForm 和 colProps 两个属性的处理

示例完整实现: codesandbox.io/s/vjdesign-…

预览效果:kyjis.csb.app/

可视化设计器:GitHub Gitee