學習的過程,必定是要挑戰一些複雜的頁面和組件的。本來是想着寫一個小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