美文网首页
可维护的Vue表单实践

可维护的Vue表单实践

作者: 陈柴盐 | 来源:发表于2021-06-19 15:08 被阅读0次

需求:含有多种优惠券,每种优惠券的规则不一致,如何最大限度上编写一个可以维护的优惠券创建的表单

满减券

image-20210619140241927.png

折扣券

image-20210619141210578.png

无门槛优惠券

image-20210619140324421.png

技术:

vue2+elementUI

一些要点:

1.为什么是直接在el-form-item上直接加:rules

    elementUI官方的案例中通常都是在data中再加上rule做统一管理,但是实际开发过程中,经常会添加新的字段或移除旧的字段,这时还要到data下面找到对应的rule比较烦人,而且对于折扣券这种根据动态启用限定减免金额的表单,如果放在rule里面可能会遇到需要重置校验表单项这些头疼的操作,:rules直接绑定el-form-item再配合v-if,可以比较友好得解决这种问题



2.组件中validate方法设计成Promise的原因

    elementUI的官方示例里是 表单.validate() 之后就是上传到后台的方法,但是很多时候表单都异常复杂,可能点击一次提交按钮涉及到多个表单,每个表单都得校验,为此我们可能会试图把两个表单合并到一个组件内,但是这样的日后一个组件的内部就会有非常多的代码,因此我把elementUI的validate再套一层Promise,这样就可以在想要验证对应的表单时获取对应的promise对象就好



3.关于组件之间是如何切换的

    如果使用v-if的话,维护起来会很恶心,尤其是面对多个if条件的时候,因为vue采用的是模板语言,v-if和下面的v-else-if间隔非常远,中间还夹杂一堆的html代码,涉及改动if条件的时候,可能就把其中一个v-else-if的条件遗漏了,这里采用了策略模式实现动态切换表单,关于Vue中如何使用策略模式,https://juejin.cn/post/6844903768333500429中有详细介绍



4.关于自定义组件

    折扣那里有一个满多少打几折的表单项,对应运营人员而言,一个东西要打9折,前端输入的时候那么应该也是数字9,但是后台计算的时候是金额*0.9,这时涉及到折扣转百分比的,有一种方法就是前端提交到后台的时候代码上实现折扣转换百分比,后台回显给前端的时候前端代码实现百分比转折扣,整个过程异常麻烦,我们其实可以通过自定义组件的方式实现,显示的数字和真实数字之间的转换,详细可以看自定义折扣组件

满减优惠逻辑

<template>
    <el-form :model="coupon" ref="coupon" label-width="100px" class="form-item-inline">
        <el-form-item label="满减规则" prop="name">
            <span>满</span>

                <el-form-item prop="condition"  :rules="[
                        { required: true, message: '请输入满减条件', trigger: 'blur' }
                ]">
                    <el-input-number v-model="coupon.condition" :precision="2" :step="0.1" :min="0" :controls="false"></el-input-number>
                </el-form-item>
            <span>减</span>
                <el-form-item prop="amount" :rules="[
                        { required: true, message: '请输入满减金额', trigger: 'blur' }
                ]">
                    <el-input-number v-model="coupon.amount" :precision="2" :step="0.1" :min="0" :controls="false"></el-input-number>
                </el-form-item>
            <span>元</span>
        </el-form-item>
    </el-form>
</template>

<script>
    export default {
        name: "priceBreakCoupon",
        data(){
            return{
                coupon:{
                    condition:undefined,
                    amount:undefined
                }
            }
        },
        methods:{
            validate() {
                return new Promise(((resolve) => {
                    this.$refs['coupon'].validate((valid) => {
                        if (valid) {
                            resolve(valid);
                        } else {
                            resolve(false)
                        }
                    });
                }));
            },
            getValue() {
                return this.coupon
            },
            setValue(data) {
                this.coupon={...this.coupon,...data}
            }
        }
    }
</script>

无门槛优惠逻辑

<template>
    <el-form :model="coupon" ref="coupon" label-width="100px" class="form-item-inline">
        <el-form-item label="券面金额" prop="amount" :rules="[
                        { required: true, message: '请输入最多优惠金额', trigger: 'blur' }
                ]">
            <el-input-number v-model="coupon.amount" :precision="2" :step="0.1" :min="0" :controls="false"></el-input-number>
            <span>元</span>
        </el-form-item>
    </el-form>
</template>

<script>
    export default {
        name: "noThresholdCoupon",
        data(){
            return{
                coupon:{
                    amount:undefined
                }
            }
        },
        methods:{
            validate() {
                return new Promise(((resolve) => {
                    this.$refs['coupon'].validate((valid) => {
                        if (valid) {
                            resolve(valid);
                        } else {
                            resolve(false)
                        }
                    });
                }));
            },
            getValue() {
                return this.coupon
            },
            setValue(data) {
                this.coupon={...this.coupon,...data}
            }
        }
    }
</script>

折扣优惠逻辑

<template>
    <el-form :model="coupon" ref="coupon" label-width="100px" class="form-item-inline">
        <el-form-item label="打折规则" prop="name"  >
            <span>满</span>

                <el-form-item prop="condition"  :rules="[
                        { required: true, message: '请输入满减条件', trigger: 'blur' }
                ]" class="inline-form-item">
                    <el-input-number v-model="coupon.condition" :precision="2" :step="0.1" :min="0" :controls="false"></el-input-number>
                </el-form-item>

            <span class="line">打</span>
                <el-form-item prop="discount" :rules="[
                        { required: true, message: '请输入折扣', trigger: 'blur' }
                ]" class="inline-form-item">
                    <Discount v-model="coupon.discount" :precision="1" :step="0.1" :controls="false"></Discount>
                </el-form-item>
                <span class="line">折</span>
        </el-form-item>
        <el-form-item label="启用限减" prop="thresholdEnable">
            <el-switch v-model="coupon.thresholdEnable"></el-switch>
        </el-form-item>
        <el-form-item v-if="coupon.thresholdEnable" label="限减金额" prop="threshold" :rules="[
                        { required: true, message: '请输入最多优惠金额', trigger: 'blur' }
                ]">
            <el-input-number v-model="coupon.threshold" :precision="2" :step="0.1" :min="0" :controls="false"></el-input-number>
        </el-form-item>
    </el-form>
</template>

<script>
    import Discount from "@/components/Discount";
    export default {
        name: "discountCoupon",
        components:{
            Discount
        },
        data(){
            return{
                coupon:{
                    condition:undefined,
                    discount:undefined,
                    thresholdEnable:false,
                    threshold:undefined
                }
            }
        },
        methods:{
            validate() {
                return new Promise(((resolve) => {
                    this.$refs['coupon'].validate((valid) => {
                        if (valid) {
                            resolve(valid);
                        } else {
                            resolve(false);
                        }
                    });
                }));
            },
            getValue() {
                return this.coupon
            },
            setValue(data) {
                this.coupon={...this.coupon,...data}
            }
        }
    }
</script>

表单本身

<template>
    <div>
        <el-radio-group v-model="couponType" class="choose-type">
            <el-radio-button label="满减券"></el-radio-button>
            <el-radio-button label="折扣券"></el-radio-button>
            <el-radio-button label="无门槛"></el-radio-button>
        </el-radio-group>
        <component :is="couponCom" ref="forms"/>

    </div>
</template>

<script>
    import PriceBreakCoupon from './priceBreakCoupon'
    import DiscountCoupon from './discountCoupon'
    import NoThresholdCoupon from './noThresholdCoupon'

    export default {
        name: "index",
        data(){
          return{
              couponType:"满减券"
          }
        },
        computed:{
            couponCom() {
                const statusMap = {
                     "满减券": PriceBreakCoupon,
                    "折扣券": DiscountCoupon,
                    "无门槛": NoThresholdCoupon
                }
                return statusMap[this.couponType]
            }
        },
        methods:{
            async validate() {
                return await this.$refs['forms'].validate();
            },
             getValue() {
               return  new Promise( (resolve)=>{
                        let formData = this.$refs['forms'].getValue();
                        resolve({couponType:this.couponType,formData:formData})
                });
            },
             setValue(data) {
                 this.couponType = data.couponType;
                 this.$nextTick(()=>{
                     this.$refs['forms'].setValue(data.formData);
                 })
            }
        }
    }
</script>

创建表单

<template>
    <div>
        <Form ref="form"/>
        <el-button type="primary" @click="onSubmit">立即创建</el-button>
    </div>
</template>

<script>
    import Form from './form/index'
    export default {
        name: "create",
        components:{
            Form
        },
        methods:{
            async onSubmit(){
                let validate = await this.$refs['form'].validate();
                if (validate) {
                    let value = await this.$refs['form'].getValue();
                    console.log(JSON.stringify(value))
                }

            }
        }
    }
</script>

编辑表达

<template>
    <div>
        <Form ref="form"/>
        <el-button type="primary" @click="onSubmit">编辑</el-button>
    </div>
</template>

<script>
    import Form from './form/index'
    export default {
        name: "edit",
        components:{
            Form
        },
        mounted() {
            this.onShow()
        },
        methods:{
            onShow() {
                let data = {
                    "couponType": "折扣券",
                    "formData": {
                        "condition": 100,
                        "discount": 0.75,
                        "thresholdEnable": true,
                        "threshold": 10
                    }
                };
                this.$refs['form'].setValue(data);
            },
            async onSubmit(){
                let validate = await this.$refs['form'].validate();
                if (validate) {
                    let value = await this.$refs['form'].getValue();
                    console.log(JSON.stringify(value))
                }
            }
        }
    }
</script>

自定义折扣组件:

<template>
    <el-input-number v-model.number="discount"  :min="1" :max="10" v-bind="$attrs"></el-input-number>
</template>

<script>
    import Big from 'big.js'
    export default {
        name: "Discount",
        props:{
          value:{
              type:Number,
              default:10
          }
        },
        computed:{
            discount:{
                get() {
                    return 10*this.value
                },
                set(currentValue) {
                    if (!currentValue) {
                        currentValue=10
                    }
                    let big = new Big(currentValue);
                    let actualValue = big.div(10).toPrecision(2);
                    this.$emit('input',Number(actualValue))
                }
            }
        }
    }
</script>

源码:https://gitee.com/ChaiYe/elementui-multi-form

原创文章,转载请注明出处:[https://www.jianshu.com/p/f563cc6b39dd]

相关文章

网友评论

      本文标题:可维护的Vue表单实践

      本文链接:https://www.haomeiwen.com/subject/kstdyltx.html