我再也不想写 Form 和 Table 组件了💥|用一小时来开发提效小工具

简介: 我再也不想写 Form 和 Table 组件了💥|用一小时来开发提效小工具

我很烦


我的上一篇文章LowCode + 团队组件设计规范 = 灵光一闪 ?提到过,我有规范化标准化生产业务基础组件的想法。每次写这样一个组件差异也不是很大,每次都要有同样的 api,同样的 props,写多了就产生了厌烦。


没错,我就是一个很容易厌倦的工程师。好烦哦~

厌倦了怎么办呢,想办法解决啊。


没错,虽然我是一个很容易厌倦的工程师,但是我还是有这该死的责任感。好烦哦~

用技术手段,用可视化界面,去产生那些没啥营养的代码。


啊,我这该死的无处安放的魅力与中二气息。好烦哦,我好喜欢我自己「🐶 狗头」

所以,开搞开搞,整个编码过程大约一个小时,比较简单~


一小时编码


网络异常,图片无法展示
|


整体的思路就很简单:


网络异常,图片无法展示
|


在页面进行操作后生成中间数据,之后通过中间数据生成代码。下面我分别介绍 Form 和 Table 我分别写了什么。


Form

网络异常,图片无法展示
|


props:

  • disabled
  • disabledFileds

methods:

  • getData
  • setData
  • clearData
  • validate
  • clearValidate


数据结构:


Array.<{
    isInline: Boolean,
    label: String,
    key: String,
    type: String,
    required: Boolean
}>


作为表单要包含所有常见表单项:


typeoOtions: [{
    type: "RADIO",
  },{
    type: "CHECKBOX",
  },{
    type: "INPUT"
  }, {
    type: "INPUTNUMBER"
  }, {
    type: "SELECT"
  },{
    type: "CASCADER"
  },{
    type: "SWITCH"
  }, {
    type: "TIMEPICKER"
  }, {
    type: "DATEPICKER"
  }, {
    type: "DATETIMEPICKER"
  }, {
    type: "RATE"
  }, {
    type: "CUSTMER"
  }
],


生成代码的工具方法:


const optionTypes = [
  'RADIO',
  'CHECKBOX',
  'SELECT',
  'CASCADER',
];
const getFormItem = (schemaItem) => {
  switch (schemaItem.type) {
    case 'RADIO':
      return `<q-radio-group v-model="formData.${schemaItem.key}">
      <q-radio v-for=“(item, index) in ${schemaItem.key}Options” :key="index" :label="item.value" :disabled="disabledFields.includes('${schemaItem.key}')" >{{ item.label }}</q-radio>
    </q-radio-group>`;
    case "CHECKBOX":
      return `<q-checkbox-group v-model="formData.${schemaItem.key}">
      <q-checkbox v-for=“(item, index) in ${schemaItem.key}Options” :key="index" :label="item.value" :disabled="disabledFields.includes('${schemaItem.key}')" >{{ item.label }}</q-checkbox>
    </q-checkbox-group>`;
    case 'INPUT':
      return `<q-input v-model="formData.${schemaItem.key}" :placeholder="请输入${schemaItem.label}" :disabled="disabledFields.includes('${schemaItem.key}')" />`
    case 'INPUTNUMBER': 
      return `<q-input-number v-model="formData.${schemaItem.key}" :disabled="disabledFields.includes('${schemaItem.key}')" />`;
    case 'SELECT':
      return `<q-select v-model="formData.${schemaItem.key}" placeholder="请选择${schemaItem.label}" :disabled="disabledFields.includes('${schemaItem.key}')">
      <q-option
        v-for=“(item, index) in ${schemaItem.key}Options” 
        :key="index"
        :label="item.label"
        :value="item.value">
      </q-option>
    </q-select>
  `;
    case 'CASCADER':
      return `<q-cascader
        v-model="formData.${schemaItem.key}"
        :options="${schemaItem.key}Options"
        :disabled="disabledFields.includes('${schemaItem.key}')" 
      />`;
    case 'SWITCH':
      return `<q-switch
        v-model="formData.${schemaItem.key}"
        :disabled="disabledFields.includes('${schemaItem.key}')"
      />`;
    case 'TIMEPICKER':
      return `<q-time-select
        placeholder="请选择${schemaItem.label}"
        v-model="formData.${schemaItem.key}" 
        :disabled="disabledFields.includes('${schemaItem.key}')"
      />`
    case 'DATEPICKER':
      return `<q-date-picker
        type="date"
        placeholder="请选择${schemaItem.label}"
        v-model="formData.${schemaItem.key}" 
        :disabled="disabledFields.includes('${schemaItem.key}')"
      />`;
    case 'DATETIMEPICKER':
      return `<q-date-picker
        type="datetime"
        placeholder="请选择${schemaItem.label}"
        v-model="formData.${schemaItem.key}" 
        :disabled="disabledFields.includes('${schemaItem.key}')"
      />`;
    case 'RATE':
      return `<q-rate 
        v-model="formData.${schemaItem.key}" 
        :disabled="disabledFields.includes('${schemaItem.key}')"
      />`;
    case 'CUSTMER':
    default:
      return `<!-- dom: v-model=“formData.${schemaItem.key}” -->`;
  }
};
export const getFormCode = (schema) => {
  return `<template>
  <q-form
    ref="form"
    :model="formData"
    :rules="rules"
    :disabled="disabled"
  >
    ${
      schema.map(item => `<q-form-item label="${item.label}" prop="${item.key}" ${item.isInline?'class="inline-form-item"':''}>
        ${getFormItem(item)}
      </q-form-item>`).join('\n')
    }
  </q-form>                                   
  </template>
  <script>
  const getBaseCustomFormData = () => ({
    ${
      schema.map(item => `${item.key}: null`).join(',\n')
    }
  })
  export default {
  props: {
    disabled: {
      type: Boolean,
      default: false
    },
    // Array.<String>
    disabledFields: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      formData: getBaseCustomFormData(),
      ${
        schema.filter(item => optionTypes.includes(item.type)).map(item => `${item.key}Options: []`).join(',\n')
      },
      rules: {
        ${
          schema.filter(item => item.required).map(item => `
            ${item.key}: [
              { required: true, message: '请输入${item.label}', trigger: 'blur' }
            ]
          `).join(',\n')
        }
      },
    };
  },
  methods: {
    setData(data) {
      this.formData = Object.assign(getBaseCustomFormData(), data);
    },
    getData() {
      return Object.assign({}, this.formData);
    },
    clearData() {
      this.formData = getBaseCustomFormData();
    },
    validate() {
      return this.$refs.form.validate();
    },
    clearValidate () {
      this.$refs.form.clearValidate();
    },
  }
  };
  </script>
  <style lang="scss" scoped>
  .inline-form-item {
    display: inline-block;
    width: 50%;
    vertical-align: top;
  }
  </style>
  `
}


Table

网络异常,图片无法展示
|


props:

  • filter
  • selectable

methods:

  • reload
  • gotoFirstPage
  • getSelectionInfo
  • setSelectionInfo

event:

  • selectionChange


数据结构:


Array.<{
    type: 'normal'|'selection',
    prop: String,
    title: String,
    isCustmer: Boolean
}>


生成代码的工具方法:


const getTableColumn = (schemaItem) => {
  if(schemaItem.type == 'selection') {
    return `<pro-column 
      type="selection" 
      :selectable="selectable"
      :enable-cross-page-selection="false" 
    />`;
  } else if(schemaItem.isCustmer) {
    return `<pro-column prop="${schemaItem.prop}" title="${schemaItem.title}">
      <template #default="{ row }">
        {{ row.${schemaItem.prop} }}
      </template>
  </pro-column>`;
  } else {
    return `<pro-column prop="${schemaItem.prop}" title="${schemaItem.title}" />`;
  }
};
export const getTableCode = (schema) => {
  return `<template>
  <pro-table
    ref="table"
    :pagination-options="PAGE_OPTIONS"
    :fetch-data="fetchData"
    @selection-change="selectionChange"
  > 
    ${
      schema.map(item => `${getTableColumn(item)}`).join('\n')
    }
    <pro-column
      v-if="$slots.operation || $scopedSlots.operation"
      title="操作"
      prop="operation"
    >
      <template #default="{ row }">
        <slot name="operation" :row="row" />
      </template>
    </pro-column>
  </pro-table>
</template>
<script>
const PAGE_OPTIONS = {
  defaultPageSize: 20,
  pageSizeOptions: [10, 20, 50, 100],
  hideOnSinglePage: false,
};
export default {
  props: {
    filter: {
      type: Object,
      default: null,
    },
    ${
      schema[0]?.type == 'selection'? `selectable: {
        type: Function,
        default: () => true
      }`: ''
    }
  },
  watch: {
    filter: {
      deep: true,
      handler() {
        this.reload();
      },
    },
  },
  data() {
    return {
      PAGE_OPTIONS,
    };
  },
  methods: {
    async fetchData({ pagination }) {
      try {
      } catch (err) {
        this.$message.error("获取列表失败");
        return {
          total: 0,
          items: [],
        };
      }
    },
    selectionChange({selectedRows,isAll,exceptedRows}) {
      this.$emit('selectionChange', {selectedRows,isAll,exceptedRows});
    },
    reload() {
      this.$refs.table.reload();
    },
    gotoFirstPage() {
      this.$refs.table.gotoFirstPage(true);
    },
    getSelectionInfo() {
      return this.$refs.table.getSelectionInfo();
    },
    setSelectionInfo({ selectedRows, isAll, exceptedRows }) {
      this.$refs.table.setSelectionInfo({ selectedRows, isAll, exceptedRows });
    }
  },
};
</script>
`;
}


说不出再见


网络异常,图片无法展示
|


整片文章难度不高,但是可以提升自己的开发效率,就像我在我之前的年终总结「寒草呈献」我的肩上是风,风上是闪烁的星群✨|致直面焦虑与本心的 2021所说的,我们无法避免工作中存在重复,但是我们可以想办法去避免重复的劳作,使自己摆脱西西弗斯式的工作。


✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨

君不见,黄河之水天上来,奔流到海不复回。
君不见,高堂明镜悲白发,朝如青丝暮成雪。
人生得意须尽欢,莫使金樽空对月。
天生我材必有用,千金散尽还复来。

✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨


下一篇文章再会~


相关文章
Maximum call stack size exceeded报错的原因及解决办法
Maximum call stack size exceeded报错的原因及解决办法
4492 0
|
JavaScript 前端开发 数据格式
LayUI前框框架普及版(三)
LayUI前框框架普及版
615 0
|
设计模式 JSON 前端开发
前端框架Layui实现动态树效果(书籍管理系统左侧下拉列表)(一)
前端框架Layui实现动态树效果(书籍管理系统左侧下拉列表)
797 0
|
JavaScript
原生js使用editor.js
原生项目中使用下一代块样式编辑器editor.js,自由,使用愉快。
原生js使用editor.js
|
JSON 移动开发 缓存
20+个可视化搭建工具,一次玩个够
无论大公司还是小公司,我们开发前端工程时候,项目工程又很多类似的功能或者页面,开发经常是加班加点搬砖去做一些无成长反复操作的工作,看键盘上 ctrle 键已经被磨掉了漆,C 和V 也马上磨白了,那对于开发如何把这些重复的工作用机器去解决?在前端资源紧缺的情况下,是否可直接有工具直接就可以搭建出我想要的前端页面?于是业界的页面可视化搭建工具就出现了,本文会介绍目前最流行的页面可视化搭建工具,也会提供一些开源的可视化搭建项目供大家参考。
3130 0
20+个可视化搭建工具,一次玩个够
|
10月前
|
SQL 数据管理 API
【产品升级】Dataphin V5.2 全新上线:四大能力升级,数据管理更统一、更智能!
Dataphin是阿里巴巴推出的数据建设与治理平台,提供全链路数据服务,助力企业构建标准化数据资产体系。V5.2版本新增“数据资产一站式运营平台”,引入X-数据管家、X-ETL等智能应用,提升数据运营效率。开发平台全面升级,支持多云复杂环境,强化API行级权限管控,保障数据安全。新版还适配国际化多时区场景,助力企业高效协同,释放数据价值。
638 9
|
前端开发 JavaScript
【项目笔记】:elementui下拉框数据太多造成页面卡顿怎么解决?
针对前端下拉框数据过多造成页面卡顿,元芳你怎么看?
1050 2
|
存储 开发框架 前端开发
EAV模型(实体-属性-值)的设计和低代码的处理方案(2)--数据的查询处理
EAV模型(实体-属性-值)的设计和低代码的处理方案(2)--数据的查询处理
|
存储 NoSQL 关系型数据库
EAV模型(实体-属性-值)的设计和低代码的处理方案(1)
EAV模型(实体-属性-值)的设计和低代码的处理方案(1)
|
移动开发 前端开发 JavaScript
技术笔记:sortable的基本属性
技术笔记:sortable的基本属性
503 0