可維護(hù)的Vue表單實(shí)踐

需求:含有多種優(yōu)惠券,每種優(yōu)惠券的規(guī)則不一致,如何最大限度上編寫(xiě)一個(gè)可以維護(hù)的優(yōu)惠券創(chuàng)建的表單

滿減券

image-20210619140241927.png

折扣券

image-20210619141210578.png

無(wú)門檻優(yōu)惠券

image-20210619140324421.png

技術(shù):

vue2+elementUI

一些要點(diǎn):

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

    elementUI官方的案例中通常都是在data中再加上rule做統(tǒng)一管理,但是實(shí)際開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)添加新的字段或移除舊的字段,這時(shí)還要到data下面找到對(duì)應(yīng)的rule比較煩人,而且對(duì)于折扣券這種根據(jù)動(dòng)態(tài)啟用限定減免金額的表單,如果放在rule里面可能會(huì)遇到需要重置校驗(yàn)表單項(xiàng)這些頭疼的操作,:rules直接綁定el-form-item再配合v-if,可以比較友好得解決這種問(wèn)題



2.組件中validate方法設(shè)計(jì)成Promise的原因

    elementUI的官方示例里是 表單.validate() 之后就是上傳到后臺(tái)的方法,但是很多時(shí)候表單都異常復(fù)雜,可能點(diǎn)擊一次提交按鈕涉及到多個(gè)表單,每個(gè)表單都得校驗(yàn),為此我們可能會(huì)試圖把兩個(gè)表單合并到一個(gè)組件內(nèi),但是這樣的日后一個(gè)組件的內(nèi)部就會(huì)有非常多的代碼,因此我把elementUI的validate再套一層Promise,這樣就可以在想要驗(yàn)證對(duì)應(yīng)的表單時(shí)獲取對(duì)應(yīng)的promise對(duì)象就好



3.關(guān)于組件之間是如何切換的

    如果使用v-if的話,維護(hù)起來(lái)會(huì)很惡心,尤其是面對(duì)多個(gè)if條件的時(shí)候,因?yàn)関ue采用的是模板語(yǔ)言,v-if和下面的v-else-if間隔非常遠(yuǎn),中間還夾雜一堆的html代碼,涉及改動(dòng)if條件的時(shí)候,可能就把其中一個(gè)v-else-if的條件遺漏了,這里采用了策略模式實(shí)現(xiàn)動(dòng)態(tài)切換表單,關(guān)于Vue中如何使用策略模式,https://juejin.cn/post/6844903768333500429中有詳細(xì)介紹



4.關(guān)于自定義組件

    折扣那里有一個(gè)滿多少打幾折的表單項(xiàng),對(duì)應(yīng)運(yùn)營(yíng)人員而言,一個(gè)東西要打9折,前端輸入的時(shí)候那么應(yīng)該也是數(shù)字9,但是后臺(tái)計(jì)算的時(shí)候是金額*0.9,這時(shí)涉及到折扣轉(zhuǎn)百分比的,有一種方法就是前端提交到后臺(tái)的時(shí)候代碼上實(shí)現(xiàn)折扣轉(zhuǎn)換百分比,后臺(tái)回顯給前端的時(shí)候前端代碼實(shí)現(xiàn)百分比轉(zhuǎn)折扣,整個(gè)過(guò)程異常麻煩,我們其實(shí)可以通過(guò)自定義組件的方式實(shí)現(xiàn),顯示的數(shù)字和真實(shí)數(shù)字之間的轉(zhuǎn)換,詳細(xì)可以看自定義折扣組件

滿減優(yōu)惠邏輯

<template>
    <el-form :model="coupon" ref="coupon" label-width="100px" class="form-item-inline">
        <el-form-item label="滿減規(guī)則" prop="name">
            <span>滿</span>

                <el-form-item prop="condition"  :rules="[
                        { required: true, message: '請(qǐng)輸入滿減條件', 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: '請(qǐng)輸入滿減金額', 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>

無(wú)門檻優(yōu)惠邏輯

<template>
    <el-form :model="coupon" ref="coupon" label-width="100px" class="form-item-inline">
        <el-form-item label="券面金額" prop="amount" :rules="[
                        { required: true, message: '請(qǐng)輸入最多優(yōu)惠金額', 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>

折扣優(yōu)惠邏輯

<template>
    <el-form :model="coupon" ref="coupon" label-width="100px" class="form-item-inline">
        <el-form-item label="打折規(guī)則" prop="name"  >
            <span>滿</span>

                <el-form-item prop="condition"  :rules="[
                        { required: true, message: '請(qǐng)輸入滿減條件', 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: '請(qǐng)輸入折扣', 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: '請(qǐng)輸入最多優(yōu)惠金額', 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="無(wú)門檻"></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,
                    "無(wú)門檻": 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>

創(chuàng)建表單

<template>
    <div>
        <Form ref="form"/>
        <el-button type="primary" @click="onSubmit">立即創(chuàng)建</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>

編輯表達(dá)

<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

原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處:[http://www.itdecent.cn/p/f563cc6b39dd]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容