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

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

大家好,我是寒草😈,一只工作一年出头的草系码猿🐒
如果喜欢我的文章,可以关注 ➕ 点赞,与我一同成长吧~
加我微信:hancao97,邀你进群,一起学习交流,成为更优秀的工程师~

「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。

我很烦

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

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

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

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

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

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

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

一小时编码

image.png

整体的思路就很简单:

image.png

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

Form

image.png

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

image.png

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>
`;
}
复制代码

说不出再见

image.png

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

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

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

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

下一篇文章再会~

我是寒草,微信:hancao97,欢迎加我的微信,成为我的伙伴,也可以找我拉你进微信群和伙伴们一起成长!

分类:
前端
收藏成功!
已添加到「」, 点击更改