学习的过程,必定是要挑战一些复杂的页面和组件的。本来是想着写一个小demo,以提高自己的编码水平。谁知看到实现的效果之后,还是觉得有分享的价值的。并且该业务组件,在金融app中使用率应该是极高的。
通过git图描述以下该自定义业务组件的功能要求:
初始进入该页面时,输入框获取焦点。输入转账金额7876543,在输入框下方会有对应金额繁体字 柒佰捌拾柒万
陆仟伍佰肆拾叁元整 与之匹配。且过万的金额汉字会呈现红色。若在输入框外任意位置点击使输入框失去焦点,输入的金额数字,会以一种金额的样式呈现即 7,876,543.00 。而当输入的转账金额以一种金额的样式呈现时,再次点击金额数字,输入框立马清空,下方匹配汉字清空隐藏。接着,在任何清空下,点击全部转入
按钮,输入框会自动输入全部余额。输入框右边的清空按钮跟随输入框内容显示或隐藏。
呈上该业务组件的过程截图:
先观澜一下哎该组件的代码模板结构
解说:
第4行,<span>
标签=转账金额;
第5行,<Input>
标签=输入框;
第14行,<div>
标签=清除输入框按钮;
第17行,<el-button>
标签=全额转入按钮;
第19行,<div>
标签=与输入金额数字匹配的繁体汉字;
业务逻辑代码:
<script>
// import {ToolEasy} from '../public/javascripts/index'
import ToolEasy from '../public/javascripts/ToolEasy'
export default {
name: "li-acc-input",
data() {
return {
transferNum: "",
clickReset: false,
textw: "",
textm: ""
};
},
watch: {
transferNum(nInput, oInput) {
this.callbackInput(nInput)
if (nInput.indexOf(",") > 0) {
// 失去焦点时触发,如果是金额格式显示,则不在进行toMoneyNum处理
return;
}
// 输入框下,繁体金额匹配展示逻辑
let thisRef = this;
ToolEasy.capitalAcc(nInput, function (prew, postw) {
if(!prew && !postw){
thisRef.textw = '';
thisRef.textm = '';
return;
}
if(!postw){
thisRef.textm = prew;
}else {
thisRef.textw = prew;
thisRef.textm = postw;
}
})
}
},
methods: {
transferAll() {// 全额转入
this.clickReset = true
this.transferNum = "100";
},
onblur() {// 失去焦点时触发
let thisRef = this;
setTimeout(function(){
if(thisRef.clickReset) {
// 如果点击清除,执行拦截
thisRef.clickReset = false
return;
}
thisRef.clickReset = false;
// 输入的数字到金额的转换
ToolEasy.toMoneyNum(thisRef.transferNum, function(tNum){
thisRef.transferNum = tNum
})
}, 222)
},
onFocus() {// 获取焦点时触发
let thisRef = this;
//如果是金额展示,获取焦点处理输入框置空
if (thisRef.transferNum.indexOf(',') > 0) {
thisRef.transferNum = ''
this.$refs.infocus.focus()
}
},
resetInput() {// 输入框内容清除
this.clickReset = true;
this.transferNum = "";
this.$refs.infocus.focus();
}
},
props: {// 属性声明,类型检查
allBalance: {
type: String,
default: "0.00",
},
mType: {
type: String,
default: "转账金额",
},
callbackInput: {
type: Function
}
}
};
</script>
代码解说
- 当用户输入,watch:{} 中监听transferNum的变化。16行,由父组件传入的回调方法。以实时能在父组件中获取用户在子组件的输入内容。在用户输入金额同时,23行代码中方法
ToolEasy.capitalAcc
则会将在输入框下方,展示与用户输入的金额相匹配的繁体字。其中的回调方法,将匹配的繁体金额回调回来并赋值给组件标签。 - 当用户输入之后,点击清除小图标,methods: {}中的方法resetInput()被触发,执行输入框内容清空且再次获取焦点。由于如果点击"清除"按钮一样达到输入框失去焦点的触发,且失去焦点的回调方法onblur() 会先于methods: {}中的方法resetInput() 执行。所以onblur()中通过定时器setTimeout以达到执行顺序有先后的效果。
- 当用户点击全额转入,*methods: {}中的方法transferAll()*被触发,执行输入框赋值,且繁体内容随之匹配。
- 当用胡输入金额之后,在外面点击,以致当前输入框失去焦点。methods: {}中的方法onblur()被触发。当用户为点击清除按钮时thisRef.clickReset=false,继续向下执行方法
ToolEasy.toMoneyNum
。将数字转换为金额样式结果回调到组件中,并进行赋值。 - 当用输入转账金额且数字已转为金额样式
7,876,543.00
对应逻辑thisRef.transferNum.indexOf(‘,’) > 0) ,此时当输入框再次获取焦点,输入框会被再次内容清空。即触发执行方法onFocus()
以上就是业务组件的功能,及实现的思想 ~
金额数字 匹配转 繁体字;金额数字 转 金额样式字符串;对应JS工具ToolEasy.js 的逻辑 :
/**
* des: 数字 转 繁体汉字
* acc 输入的转账金额
* callback(prew, postw) prew:万以上金额 postw:万以下金额
*/
const capitalAcc = (acc, callback) => {
// 汉字数字
const cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
// 基本单位
const cnIntRadice = ['', '拾', '佰', '仟']
// 对应整数部分的扩展单位
const cnIntunits = ['', '万', '亿', '兆']
// 对应小数部分的扩展单位
const cnDecunits = ['', '角', '分', '里']
// 整数金额后面的字符
const cnInteger = '整'
// 整数之后的单位
const cnIntLast = '元'
// 最大处理的数字
const maxNum = 9999999999999999.99
// 金额整数部分
let integerNum
// 金额小数部分
let decimalNum
// 输出金额字符串
let chineseStr = ''
// 分离金额后,使用的数组、预定义
let parts
// console.log('===capitalAcc 打印===>>> 方法进入')
if(acc === '' || acc < 0) {
callback('', '')
return ''
}
acc = parseFloat(acc)
if(acc >= maxNum) {
//如果超出最大值
callback('', '')
return ''
}
if(acc === 0){
chineseStr = cnNums[0] + cnIntLast + cnInteger
callback(chineseStr, '')
return;
}
// 转换成字符串
acc = acc.toString()
if(acc.indexOf('.') < 0) {
integerNum = acc
decimalNum = ''
} else {
parts = acc.split('.')
integerNum = parts[0]
decimalNum = parts[1].substr(0, 4)
}
// 获取整数部分的转换
if(parseInt(integerNum, 10) > 0) {
let zeroCount = 0
const IntLen = integerNum.length
for (let i = 0; i < IntLen; i++) {
const n = integerNum.substr(i, 1)
const p = IntLen - i -1
const q = p / 4
const m = p % 4
if (n === '0') {
zeroCount++
} else {
if(zeroCount > 0) {
chineseStr += cnNums[0]
}
// 归 0
zeroCount = 0
chineseStr += cnNums[parseInt(n)] + cnIntRadice[m]
}
if(m === 0 && zeroCount < 4) {
chineseStr += cnIntunits[q]
}
}
chineseStr += cnIntLast
}
// 小数部分
if (decimalNum !== '') {
const decLen = decimalNum.length
for (let i = 0; i < decLen; i++) {
const n = decimalNum.substr(i, 1)
if (n !== '0') {
chineseStr += cnNums[Number(n)] + cnDecunits[i]
}
}
}
if (chineseStr === ''){
chineseStr += cnNums[0] + cnIntLast + cnInteger
} else if(decimalNum === '') {
chineseStr += cnInteger
}
// 如,贰拾贰万 贰仟叁佰肆拾捌元整 len=12 lastIndex = 9
let index = chineseStr.lastIndexOf('万')
if (index > 0) {
let prew = chineseStr.substr(0, index+1)
let postw = chineseStr.substr(index + 1)
// console.log('===capitalAcc 打印1th prew, postw===>>>', prew, postw)
callback(prew, postw)
} else {
// console.log('===capitalAcc 打印2th chineseStr===>>>', chineseStr)
callback(chineseStr, '')
}
}
/**
* des: 输入的金额数字 转换 金额格式
* acc: 输入的转账金额
* callback(tNum) tNum:已转金额格式
*/
const toMoneyNum = (acc, callback) => {
// console.log('===toMoneyNum 打印===>>> 方法进入')
if (acc) {
if (isNaN(acc)){
callback('')
return ''
}
acc = typeof acc === 'string' ? parseFloat(acc) : acc // 判断是否是字符串,是就转数字
acc = acc.toFixed(2)
acc = Number.parseFloat(acc)
acc = acc.toLocaleString() // 转换成金额显示的格式方法
// 判断是否有小数
if (acc.indexOf('.') < 0) {
acc = acc + '.00'
}
// console.log('===toMoneyNum 打印===>>>', acc)
callback(acc)
}
}
const ToolEasy = {}
ToolEasy.capitalAcc = capitalAcc
ToolEasy.toMoneyNum = toMoneyNum
export default ToolEasy