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

折扣券

无门槛优惠券

技术:
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]
网友评论