[设计器 vjdesign] 动态表单设计器自定义属性编辑器

1,895 阅读2分钟

vjdesign 是一个具有高扩展性的动态表单设计器,本示例实现一个自定以属性编辑器例子

说明

自定义组件

首先做一个 vue 自定义组件

Vue.component("custom-number", {
  template: `<div><button type="button" @click="mut">-</button> {{value}} <button type="button" @click="plus">+</button></div>`,
  props: { value: Number, default: 0 },
  methods: {
    plus() {
      this.$emit("input", (this.value || 0) + 1);
    },
    mut() {
      this.$emit("input", Math.max((this.value || 0) - 1, 0));
    }
  }
});

editor 方法用于注册属性编辑器,第一个参数就是设计器配置文件中 editor 要设置的值

然后定义一个属性编辑器,是一个方法返回一个对象,该对象的定义方法同 jformer 里定义一样也是动态表单组件的定义,component 是组件名这里使用刚才定义的组件, 参数传递了一个 path,这个 path 就是组件在设计器编辑的时候正在编辑的属性名,将这个 path 设置到组件数据 model 上实现更新组件相应属性

 window.vjdesign.default.use(({ editor }) => {
  editor("customNumber", (path) => {
    return {
      component: "custom-number",
      model: [path]
    };
  });
});

在配置文件中组件属性上使用自定义的属性编辑器

{
  name: "el-row",
  label: "行",
  group: "element",
  properties: [
    {
      name: "fieldOptions.props.gutter",
      label: "间隔",
      group: "组件",
      // 这里就是注册的属性编辑器名称
      editor: "customNumber"
    }
  ],
  designer: "classContainer"
}

要想使用自定义组件或第三方组件作为属性编辑器,在 vue 项目中要先引用这个组件

使用已有组件并传递参数

实现将 el-silder 作为属性编辑器,并传递参数限制值的范围和步长

首先定义一个组件属性编辑器并注册,除了 path 参数,options 是配置文件里定义的额外配置信息,通常作为编辑器组件属性

window.vjdesign.default.use(({ editor }) => {
  editor("elSilder", (path, options) => {
    return {
      component: "el-slider",
      model: [path],
      fieldOptions: { props: options }
    };
  });
});

设计器配置文件里使用这个属性编辑器

{
  name: "el-col",
  label: "列",
  group: "element",
  properties: [
    {
      name: "fieldOptions.props.span",
      label: "列宽",
      group: "组件",
      default: 12,
      editor: {
        // 属性编辑器名称
        name: "elSilder",
        // 属性编辑器属性
        options: { step: 1, min: 1, max: 24 }
      }
    }
  ],
  designer: "classContainer"
}

完整示例

html 页

直接将以下实现存成 html 就可以查看效果

<!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>
    <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>
      const Vue = window.Vue;

      Vue.component("custom-number", {
        template: `<div><button type="button" @click="mut">-</button> {{value}} <button type="button" @click="plus">+</button></div>`,
        props: { value: Number, default: 0 },
        methods: {
          plus() {
            this.$emit("input", (this.value || 0) + 1);
          },
          mut() {
            this.$emit("input", Math.max((this.value || 0) - 1, 0));
          }
        }
      });

      window.vjdesign.default.use(({ editor }) => {
        editor("customNumber", (path) => {
          return {
            component: "custom-number",
            model: [path]
          };
        });

        editor("elSilder", (path, options) => {
          return {
            component: "el-slider",
            model: [path],
            fieldOptions: { props: options }
          };
        });
      });

      new Vue({
        data() {
          return {
            config: {
              datasource: {},
              listeners: [],
              fields: [
                {
                  component: "div",
                  children: [
                    {
                      component: "el-row",
                      children: [
                        {
                          component: "el-col",
                          fieldOptions: {
                            props: {
                              span: 10
                            }
                          }
                        },
                        {
                          component: "el-col",
                          fieldOptions: {
                            props: {
                              span: 12
                            }
                          }
                        },
                        {
                          component: "el-col",
                          fieldOptions: {
                            props: {
                              span: 12
                            }
                          }
                        },
                        {
                          component: "el-col",
                          fieldOptions: {
                            props: {
                              span: 16
                            }
                          }
                        }
                      ]
                    }
                  ]
                }
              ],
              model: {}
            },
            profile: {
              components: [
                {
                  name: "el-row",
                  label: "行",
                  group: "element",
                  properties: [
                    {
                      name: "fieldOptions.props.gutter",
                      label: "间隔",
                      group: "组件",
                      editor: "customNumber"
                    }
                  ],
                  designer: "classContainer"
                },
                {
                  name: "el-col",
                  label: "列",
                  group: "element",
                  properties: [
                    {
                      name: "fieldOptions.props.span",
                      label: "列宽",
                      group: "组件",
                      default: 12,
                      editor: {
                        name: "elSilder",
                        options: { step: 1, min: 1, max: 24 }
                      }
                    }
                  ],
                  designer: "classContainer"
                }
              ]
            }
          };
        }
      }).$mount("#app");
    </script>
  </body>
</html>

相关链接

设计器: Github Gitee