需求:含有多種優(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]