大家好,我是寒草😈,一只工作一年出头的草系码猿🐒
如果喜欢我的文章,可以关注 ➕ 点赞,与我一同成长吧~
加我微信:hancao97,邀你进群,一起学习交流,成为更优秀的工程师~
「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。
我很烦
我的上一篇文章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所说的,我们无法避免工作中存在重复,但是我们可以想办法去避免重复的劳作,使自己摆脱西西弗斯式的工作。
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
君不见,黄河之水天上来,奔流到海不复回。
君不见,高堂明镜悲白发,朝如青丝暮成雪。
人生得意须尽欢,莫使金樽空对月。
天生我材必有用,千金散尽还复来。
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
下一篇文章再会~
我是寒草,微信:hancao97,欢迎加我的微信,成为我的伙伴,也可以找我拉你进微信群和伙伴们一起成长!