1.公共表单组件
//commonForm.vue
<script>
import {TEXT,SELECT,PASSWORD,TEXTAREA,RADIO,DATE_PICKER
} from '@/conf/uiTypes'
import { deepClone } from '@/utils'
export default {name: 'GFormCreator',props: {config: { // title/itemstype: Object,required: true}},created() {const { items, cards, rules } = this.config;// 绑定表单验证器thisfor (let key in rules) {rules[key].forEach(r => {// 若该方法是全局方法,第二次bind会失效,因为bind只能绑定一次if (r.validator) {r.validator = r.validator.bind(this)}}) }if (cards) {cards.forEach(card => {this.reactiveFields(card.children);})} else if (items) {this.reactiveFields(items);}},data() {return {ruleForm: {}}},methods: {reactiveFields(items) {console.log(items);if (!items) return;items.forEach((row, rowIndex) => {row.forEach((item, colIndex) => {// this.ruleForm[item.key] = item.value;// Object.defineProperty 对所有key进行响应式,更改后更新// 无法检测到动态添加的key,访问、设置,set/get都无法触发响应式 if (this.ruleForm.hasOwnProperty(item.key)) {// 异常抛出,外部方法没有捕获的画,程序结束throw new Error(`行:${rowIndex + 1}_列${colIndex + 1}` + '已经存在相同的key:' + item.key + ',value:' + item.value)}this.$set(this.ruleForm, item.key, item.value);})});},renderItem(item) {const fd = this.ruleForm;const attrs = item.attrs;switch (item.type) {case TEXT:case PASSWORD:case TEXTAREA:// v-model = @input + :valuereturn <el-input attrs={attrs} v-model={fd[item.key]} type={item.type} ></el-input>case SELECT:return <el-select attrs={attrs} v-model={fd[item.key]}>{item.options.map(opt => {return <el-option value={opt.value} label={opt.label}></el-option>})}</el-select>case DATE_PICKER:return <el-date-pickerattrs={attrs}v-model={fd[item.key]}type="date"placeholder="选择日期"></el-date-picker>case RADIO: // { label:'xxx' radios:[ { attrs:{},label:'xxx' } ] }return item?.radios?.map(radio => {console.log('radio:', fd[item.key])return <el-radioattrs={radio.attrs}v-model={fd[item.key]} label={radio.label}>{radio.title}</el-radio>})default:return <h2>未匹配{item.type}</h2>}},renderColumns(columns) {return columns.map(col => {return <el-col span={col.colspan}><el-form-item label={col.label} prop={col.key}>{this.renderItem(col)}</el-form-item></el-col>})},renderRows(rows) {return rows.map(rowArr => {return <el-row>{this.renderColumns(rowArr)}</el-row>})},getData() {return deepClone(this.ruleForm)},passData() {// submitthis.$emit('submit', deepClone(this.ruleForm));},// 外部验证// 内部验证返回数据doSubmit() {this.$refs.form.validate(valid => {if (valid) {return this.$emit('submit', deepClone(this.ruleForm));} else {console.log('验证失败');return false;}})},valid(callback) {this.$refs.form.validate(valid => {if (valid) {return callback(deepClone(this.ruleForm))} else {callback(false);console.log('验证失败');return false;}});},reset() {this.$refs.form.resetFields();}, renderCards(cards) {let { renderRows } = this;return cards.map(card => {// 渲染name和children(renderRows) return (<el-card class="box-card" header={card.name}>{card.children && renderRows(card.children)}</el-card >)// 实现方式1// let h = this.$createElement;return h('el-card', { class: 'box-card' }, [h('template', { slot: 'header' }, [h('span', card.name)]),card.children && renderRows(card.children)]);// 实现方式2return (<el-card class="box-card"><template slot="header"><span>{card.name}</span></template>{card.children && renderRows(card.children)}</el-card >);})}},render() {const { title, items, rules, cards } = this.config;const { ruleForm, $scopedSlots: { btn } } = this;return (<div class="form-box">{title && <h2>{title}</h2>} <el-form ref="form" attrs={{ model: ruleForm, }} rules={rules} label-width="80px">{cards ? this.renderCards(cards) : this.renderRows(items)}</el-form> <div class="btn-bow">{btn ? btn({ t: '我是scopod' }) : (<div><el-button type="primary" onClick={e => this.doSubmit()}>提交</el-button><el-button onClick={e => this.reset()}>重置</el-button></div>)}</div> </div>)}
}
</script><style scoped>
.el-input,
.el-select,
.form-box .el-date-editor {width: 100%;
}:deep(.el-card__header) {text-align: left;
}.box-card {margin-bottom: 10px;
}
</style>