封装公共el-form表单

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/items
            type: Object,
            required: true
        }
    },
    created() {
        const { items, cards, rules } = this.config;

        // 绑定表单验证器this
        for (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 + :value
                    return <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-picker
                        attrs={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-radio
                            attrs={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() {
            // submit
            this.$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)
                ]);
                // 实现方式2
                return (
                    <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>

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路光.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值