目录
组件说明
效果图:
?代码示例
组件说明
表单中涉及金额控件时,编辑状态下是数字格式,非编辑状态要显示千分位格式化的形式,提交到后台接口时依然是数字格式,于是用el-input组件,结合sync修饰符,实现自定义组件的v-model效果。支持格式化、自定义前缀、后缀、千分位设置以及百分比显示效果。
为什么要借助sync修饰符实现双向数据绑定,因为在vue中props是单向数据绑定,父组件通过prop给子组件下发数据,子组件通过事件给父组件发送消息。但如果直接绑定props会报警告信息,所以在子组件中实现双向数据绑定时,需要使用data的变更来转换一下。
效果图:
非编辑状态:
?编辑状态:
提交后台的数据:
?代码示例
注意:使用组件时,绑定value.sync 而非直接 v-model。
<template>
<div style="padding:40px 10px;">
<el-form size="mini" label-width="60px">
<el-row :gutter="24">
<el-col :span="6">
<el-form-item :label="'金额'">
<money :value.sync="moneyValue" :prefix="'¥'"></money>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-button type="primary" size="mini" @click="handleSub"
>提交</el-button
>
</el-row>
</el-form>
</div>
</template>
<script>
export default {
components: { money: () => import('./money.vue') },
data() {
return {
moneyValue: 12345,
}
},
methods: {
handleSub() {
this.$message.info('提交到后台的数据:' + this.moneyValue)
},
},
}
</script>
<style lang="scss" scoped></style>
<template>
<div>
<el-input
v-show="isEdit"
v-model="currentValue"
ref="validInput"
@blur="handleValueBlur"
>
<template slot="prepend" v-if="prefix">{{ prefix }}</template>
<template slot="append" v-if="suffix">{{ suffix }}</template>
</el-input>
<el-input
v-show="!isEdit"
v-model="displayValue"
@focus="handleDisplayfocus"
>
<template slot="prepend" v-if="prefix">{{ prefix }}</template>
<template slot="append" v-if="suffix">{{ suffix }}</template>
</el-input>
</div>
</template>
<script>
/** 金额编辑组件 */
export default {
/**
* 属性参数
* @member props
* @property {number|string} [value] 原始值
* @property {number} [precision=0] 精度,保留几位小数
* @property {string} [separator=,] 分隔值的符号,默认值为‘,’(英文逗号)
* @property {string} [prefix] 前缀内容,也可以用插槽定义
* @property {string} [suffix] 后缀内容,也可以用插槽定义
* @property {boolean} [percentage] 按百分比计算显示, 如value=0.2, 显示为 20%
*/
props: {
// 数字
value: [Number, String],
// 精度,保留几位小数
precision: {
type: Number,
default: 2,
},
// 分隔符
separator: {
type: String,
default: ',',
},
// 前缀
prefix: {
type: String,
default: '',
},
// 后缀
suffix: {
type: String,
default: '元',
},
// 按百分比显示
percentage: {
type: Boolean,
default: false,
},
},
data() {
return {
isEdit: false, // 默认显示格式化后内容
currentValue: this.value, // 绑定值
displayValue: this.value, // 显示的值
}
},
watch: {
value(val) {
this.currentValue = val || ''
},
currentValue(val) {
this.$emit('update:value', val)
},
},
methods: {
// 显示格式化的值
handleValueBlur() {
// if (this.currentValue.includes(',')) {
// this.currentValue = this.currentValue.replaceAll(',', '');
// }
let thousandsFormate = this.numberFormat(
this.currentValue,
this.precision,
this.separator
)
if (this.percentage) {
thousandsFormate = this.currentValue * 100 + '%'
}
this.displayValue = thousandsFormate
this.isEdit = false
},
// 开启编辑
handleDisplayfocus() {
const me = this
this.isEdit = true
setTimeout(() => {
me.$refs.validInput.focus()
}, 100)
},
/*
* 金额格式化:
* number:要格式化的数字
* decimals:保留几位小数
* thousandsSep:千分位符号
* tdecPoint:小数点符号
* */
numberFormat(number, decimals = 2, thousandsSep = ',', tdecPoint = '.') {
number = (number + '').replace(/[^0-9+-Ee.]/g, '')
if (number.indexOf(',') > -1) {
return number
}
let n = !isFinite(+number) ? 0 : +number,
prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
sep = typeof thousandsSep === 'undefined' ? ',' : thousandsSep,
dec = typeof tdecPoint === 'undefined' ? '.' : tdecPoint,
s = '',
toFixedFix = function(n, prec) {
const k = Math.pow(10, prec)
return '' + Math.ceil(n * k) / k
}
s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.')
const re = /(-?\d+)(\d{3})/
while (re.test(s[0])) {
s[0] = s[0].replace(re, '$1' + sep + '$2')
}
if ((s[1] || '').length < prec) {
s[1] = s[1] || ''
s[1] += new Array(prec - s[1].length + 1).join('0')
}
return s.join(dec)
},
},
}
</script>
<style lang="scss" scoped></style>
|