核心思想
A.利用失去焦点事件on-focus替换千分位符号
this.formInfoData[name] = this.formInfoData[name].replace(/\,/g, '')
B.利用 验证绑定的事件处理数字
(处理数字 功能有待完善,因不支持负数, 精度不够,js toFixed方法 对于数字精度处理有问题)
呵呵呵哒 主要是思想和应用 ,具体数字处理网上有很多实例。这里不做赘述。
//验证处理对象的绑定
rules: {
contractName: [{ validator: this.contractNameValid, trigger: 'blur' }],
endDate: [{ validator: this.endDateValid, type: 'date', trigger: 'change' }],
money: [ // 合同金额需要特殊处理
{ validator: this.moneyValidChange, trigger: 'change' },
{ validator: this.moneyValidBlur, trigger: 'blur' }
]
},
// 验证的处理方法
moneyValidChange (rule, val, cb) {
val = val.replace(/\,/g, '').replace('-', '')
if (this._isEmpty(val)) {
cb(new Error('请填写合同金额'))
} else if (this.isNumberInt(val)) {
cb(new Error('请输入正确数字'))
}
cb()
},
moneyValidBlur (rule, val, cb) {
val = val.replace(/\,/g, '').replace('-', '')
if (this._isEmpty(val)) {
cb(new Error('请填写合同金额'))
} else if (this.isNumberInt(val)) {
cb(new Error('请输入正确数字'))
} else {
this.signInfoData[rule.field] = parseFloat(val).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
}
cb()
},
//数字判断 具体什么要求,可以根据自己的业务自行拓展。
isNumberInt (val) {
let regPos = /^\d+(\.\d+)?$/ // 非负浮点数
if (regPos.test(val)) {
return false
} else {
return true
}
}
实战核心代码
A 如下 focus事件的绑定,
<Input v-if="item.type==='number2'" v-model="formModel[item.model]" :maxlength="16" placeholder="" type="text" @on-focus="inputFocus(item.model)" />
事件处理代码因为封装通用, 所以用emit 抛出去。
inputFocus (name) {
this.$emit('inputFocus', name)
}
实战代码如下。
实例应用
form.vue 表单。
<template>
<Form ref="signInfoForm" :rules="rules" :show-message="true" :model="signInfoData" :label-width="262">
<cus-form :datas="datas" :formModel="signInfoData" @inputFocus="inputFocus" />
</Form>
</template>
<script>
import { formatDate } from '@util/tool'
import { addProjectForms } from './singinfoOption'
import CusForm from './CusForm'
const arrayModelType = ['checkbox']
export default {
name: 'SignInfo',
components: {
CusForm
},
props: {
signType: {
default: '1',
type: String
},
tempName: {
default: '',
type: String
}
},
data () {
return {
checkboxSelect: false,
endDateType: '1',
rules: {
contractName: [{ validator: this.contractNameValid, trigger: 'blur' }],
endDate: [{ validator: this.endDateValid, type: 'date', trigger: 'change' }],
money: [ // 合同金额需要特殊处理
{ validator: this.moneyValidChange, trigger: 'change' },
{ validator: this.moneyValidBlur, trigger: 'blur' }
]
},
signInfoData: {
contractName: '',
endDate: ''
},
datas: [],
options: {
disabledDate (date) {
return date && date.valueOf() < Date.now() - 86400000
}
}
}
},
computed: {
// ...mapGetters({
// _user: '_user'
// })
},
watch: {
.........
},
mounted () {
this.datas = addProjectForms().filter((item) => {
if (item.showItem && item.showItem === '1') {
return false
} else {
return true
}
})
},
beforeDestroy () {
},
methods: {
inputFocus (name) {
this.signInfoData[name] = this.signInfoData[name].replace(/\,/g, '')
},
isNumberInt (val) {
let regPos = /^\d+(\.\d+)?$/ // 非负浮点数
if (regPos.test(val)) {
return false
} else {
return true
}
},
setupForm () {
let forms = {}
// 此处千万不要this.data 作为循环, 因为 addProjectForms 包含默认值会丢失
this._forEach(addProjectForms(), item => {
let arr = []
if (item.type === 'checkbox') {
this._forEach(item.children, o => {
o.value && arr.push(o.value)
})
}
if (!this._isNil(item.model) && item.type !== 'text') {
// 取默认值
forms[item.model] = !this._isNil(item.value) ? item.value : arrayModelType.includes(item.type) ? arr : ''
}
})
console.log('------1', this.signInfoData)
return Object.assign({}, forms, this.signInfoData)
},
contractNameValid (rule, val, cb) {
if (this._isEmpty(val)) {
cb(new Error('请输入签署名称'))
} else if (val.length > 60) {
cb(new Error('超出最长字数限制,请重新输入'))
}
cb()
},
moneyValidChange (rule, val, cb) {
val = val.replace(/\,/g, '').replace('-', '')
if (this._isEmpty(val)) {
cb(new Error('请填写合同金额'))
} else if (this.isNumberInt(val)) {
cb(new Error('请输入正确数字'))
}
cb()
},
moneyValidBlur (rule, val, cb) {
val = val.replace(/\,/g, '').replace('-', '')
if (this._isEmpty(val)) {
cb(new Error('请填写合同金额'))
} else if (this.isNumberInt(val)) {
cb(new Error('请输入正确数字'))
} else {
this.signInfoData[rule.field] = parseFloat(val).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
}
cb()
},
endDateValid (rule, val, cb) {
// 指定截止日期 时做空验证
if (this.endDateType === '2' && val === '') {
cb(new Error('请填写签署截止日'))
}
cb()
},
// 提交
singInfoSubmit (status) {
if (this.checkboxSelect) {
this.$refs['signInfoForm'].validate((valid) => {
if (valid) {
this.$emit('handleSubmit', this.getData(), status)
}
})
} else {
if (this.signInfoData.isContract === '1') {
this.$Message.info('请勾选说明内容')
} else {
this.$refs['signInfoForm'].validate((valid) => {
if (valid) {
this.$emit('handleSubmit', this.getData(), status)
}
})
}
}
},
setData (signInfo) {
if (signInfo.endDate) {
this.endDateType = '2'
signInfo.endDate = formatDate(new Date(signInfo.endDate), 'yyyy-MM-dd')
} else {
this.endDateType = '1'
}
// if (signInfo.requestTime) {
// signInfo.requestTime = formatDate(new Date(signInfo.requestTime), 'yyyy-MM-dd')
// }
if (signInfo.money) { // 合同金额格式化
signInfo.money = parseFloat(signInfo.money).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
}
Object.assign(this.signInfoData, signInfo)
console.log('------2', this.signInfoData)
},
getData () {
let obj = {}
if (this.signType === '02') {
obj = Object.assign({}, obj, this.signInfoData)
obj.money = obj.money.replace(/\,/g, '').replace('-', '')
// obj.requestTime = obj.requestTime ? formatDate(new Date(this.signInfoData.requestTime), 'yyyy-MM-dd') : ''
} else {
obj = {
contractName: this.signInfoData.contractName,
endDate: this.endDateType === '2' && this.signInfoData.endDate ? formatDate(new Date(this.signInfoData.endDate), 'yyyy-MM-dd') : '',
endDateType: this.endDateType
}
}
return obj
}
}
}
</script>
Cusform.vue 在另一篇实战也有一个类似,那个更高级。
<template>
<div class="formPanel">
<FormItem v-for="(item, index) in datas" :key="index" :label="item.label" :rules="item.rules" :prop="item.prop" :class="item.class">
<i-input v-if="item.type === 'input'" v-model.trim="formModel[item.model]" :type="item.inputType" :disabled="item.disabled" :placeholder="item.placeholder" :size="item.size" @on-enter="search" />
<RadioGroup v-if="item.type === 'radio'" v-model="formModel[item.model]">
<Radio v-for="(e, i) in item.children" :key="i" :label="e.label">
{{ e.text }}
</Radio>
<slot v-if="item.slot" :name="item.slot" />
</RadioGroup>
<CheckboxGroup v-if="item.type === 'checkbox'" v-model="formModel[item.model]" class="mycheck-group">
<Checkbox v-for="(e, i) in item.children" :key="i" :label="e.label" :disabled="e.disabled">
{{ e.text }}
</Checkbox>
</CheckboxGroup>
<Checkbox v-if="item.type === 'check'" v-model="formModel[item.model]" :label="item.checklabel" :disabled="e.disabled">
{{ e.text }}
<slot v-if="item.slot" :name="item.slot" />
</Checkbox>
<DatePicker v-if="item.type === 'datePicker'" v-model="formModel[item.model]" style="width:100%;" :value="formModel[item.model]" :type="item.pickertype ? item.pickertype : 'date'" :options="item.options" :size="item.size" :placeholder="item.placeholder" />
<i-input v-if="item.type === 'textarea'" v-model="formModel[item.model]" :autosize="item.autosize" type="textarea" :size="item.size" />
<Select v-if="item.type === 'select'" v-model="formModel[item.model]" :disabled="item.disabled" :filterable="item.filterable" :size="item.size" :placeholder="item.placeholder" @on-change="selectChange">
<Option v-for="(e, i) in item.children" :key="i" :value="e.label">
{{ e.text }}
</Option>
</Select>
<label v-if="item.type === 'text'" :size="item.size">
{{ item.text }} <slot v-if="item.slot" :name="item.slot" :params="item.params" />
</label>
<Select v-if="item.type === 'filterSelect'" v-model="formModel[item.model]" :disabled="item.disabled" :label-in-value="true" :size="item.size">
<Option v-for="(e, i) in item.children" :key="i" :value="e.code">
{{ e.name }}
</Option>
</Select>
<InputNumber
v-if="item.type==='number'"
v-model="formModel[item.model]"
style="width:100%;"
:formatter="value => `${value}`.replace(/(?=(?!\b)(\d{3})+\.)/g,',')"
:parser="value => value.replace(/$s?|(,*)/g, '')" :precision="item.precision" :min="item.min"
:max="item.max"
:disabled="item.disabled"
:placeholder="item.placeholder"
:size="item.size" />
<Input v-if="item.type==='number2'" v-model="formModel[item.model]" :maxlength="16" placeholder="" type="text" @on-focus="inputFocus(item.model)" />
<div v-if="item.type === 'inputSlot'" style="postion:relative;">
<i-input v-model="formModel[item.model]" :type="item.inputType" :disabled="item.disabled" :placeholder="item.placeholder" :size="item.size" />
<slot v-if="item.slot" :name="item.slot" :params="item.params" />
</div>
</FormItem>
</div>
</template>
<script>
export default {
name: 'CusForm',
props: {
datas: {
type: Array,
required: true
},
formModel: {
type: Object,
required: true
}
},
data () {
return {
left: ''
}
},
computed: {
},
watch: {
},
mounted () {
// this.left = this.toLeft !== '1' ? this.toLeft : (this.inline ? '0' : '200')
},
methods: {
inputFocus (name) {
this.$emit('inputFocus', name)
}
}
}
</script>
<style lang="scss">
.form-wrap {
.ivu-cascader-rel {
width: 18.75rem;
}
.phone-wrap {
.phone-zone {
width: 3.75rem;
.ivu-input {
width: 3.75rem !important;
}
}
.phone-num {
width: 14.062rem;
.ivu-input {
width: 14.062rem !important;
}
}
}
}
.mycheck-group {
overflow: hidden;
.ivu-checkbox-wrapper {
display: flex;
float: left;
align-items: center;
margin-right: 0;
min-width: 20%;
font-size: 14px;
> span {
margin-right: 9px;
}
}
}
</style>
<style lang="scss" scoped>
.form-wrap {
&.formvertical {
.btn-wrap {
margin-left: 8.125rem;
}
}
margin-top: 12px;
.btn-wrap {
display: inline-block;
margin-top: 4px;
}
.btncenter {
display: flex;
justify-content: center;
margin-top: 1.875rem;
}
}
</style>
配置文件 number2的配置。
{
type: 'number2',
label: '合同金额:',
model: 'money',
showItem: '1',
max: 999999999999999999,
min: 0,
precision: 2,
// rules: signRules.money,
prop: 'money'
},