当前位置: 首页 > news >正文

uniapp-vue3来实现一个金额千分位展示效果

前言:

        uniapp-vue3来实现一个金额千分位展示效果

实现效果:

实现目标:

1、封装组件,组件内部要实现,

  • input输入金额后,聚焦离开后,金额以千分位效果展示,
  • 聚焦后展示大写金额的弹框
  • 随时写的内容,可以用v-model传输给父级
  • 金额要有最大值,还要只能输入数字,小数后只能有2位

2、实现方法:

1)input框输入金额,并添加聚焦,离开事件

页面上添加内容:

<inputv-model="displayValue"@input="handleInput"@blur="handleBlur"@focus="handleFocus"placeholder="请输入金额"
/>

js中增加配置

const displayValue = ref('')
const rawValue = ref(0)const handleInput = (e) => {let val = e.detail.value
}// 处理失去焦点
const handleBlur = () => {
}// 处理获取焦点
const handleFocus = () => {
}

2)输入的内容,处理非数字内容,还有只能有一个小数点,小数点后添加2位限制,最大值限制

const displayValue = ref('') //千分位处理后的字段
const rawValue = ref(0)      //拿到的实际内容数据
const maxFloatNum = ref(2)  //限制小数点后几位
const maxNum = ref(100000000000) //设置最大值
const handleInput = (e) => {let val = e.detail.valueif(!val) return ''let value = val.toString().replace(/[^\d.]/g, '')if (value.length > 1 && value.startsWith('0')) {value = value.substring(1)}const min = 0const max = maxNum.value// 确保只有一个点const parts = value.split('.')if (parts.length > 2) {value = parts[0] + '.' + parts.slice(1).join('')}// 限制小数点后两位if (parts.length === maxFloatNum.value) {value = parts[0] + '.' + parts[1].slice(0, maxFloatNum.value)}// 转换为数字const numValue = parseFloat(value || 0)// 检查范围if (numValue > max) {value = max.toString()} else if (numValue < min) {value = min.toString()}rawValue.value = numValuedisplayValue.value = value}

3)聚焦和离开时候将数据转换位千分位,通过正则

// 格式化显示值(添加千分位)const formatDisplay = (value) => {const num = parseFloat(value || 0)return num.toFixed(maxFloatNum.value).replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
// 处理失去焦点
const handleBlur = () => {displayValue.value = formatDisplay(rawValue.value)
}// 处理获取焦点
const handleFocus = () => {displayValue.value = rawValue.value.toString()
}

4)来写一个大小写转换的功能,并展示到界面input上面,配合样式

js中封装小写转大写方法
//封装的小写转大写方法,适合各种场景const amountToChinese = (num)=> {const cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']const cnIntRadice = ['', '拾', '佰', '仟']const cnIntUnits = ['', '万', '亿', '兆']const cnDecUnits = ['角', '分', '毫', '厘']const cnInteger = '整'const cnIntLast = '元'if(num > maxNum.value){return '-'}// 处理负数let sign = '';if (num < 0) {sign = '负';num = Math.abs(num);}// 分离整数和小数部分let numStr = num.toString();let integerStr = '';let decimalStr = '';if (numStr.indexOf('.') !== -1) {const parts = numStr.split('.');integerStr = parts[0];decimalStr = parts[1].substring(0, 4); // 最多支持4位小数} else {integerStr = numStr;}// 处理整数部分let chineseInteger = '';if (parseInt(integerStr, 10) > 0) {let zeroCount = 0;const intLen = integerStr.length;for (let i = 0; i < intLen; i++) {const n = integerStr.charAt(i);const p = intLen - i - 1;const q = p / 4;const m = p % 4;if (n === '0') {zeroCount++;} else {if (zeroCount > 0) {chineseInteger += cnNums[0];}zeroCount = 0;chineseInteger += cnNums[parseInt(n)] + cnIntRadice[m];}if (m === 0 && zeroCount < 4) {chineseInteger += cnIntUnits[q];}}chineseInteger += cnIntLast;}// 处理小数部分let chineseDecimal = '';if (decimalStr) {for (let i = 0; i < decimalStr.length; i++) {const n = decimalStr.charAt(i);if (n !== '0') {chineseDecimal += cnNums[parseInt(n)] + cnDecUnits[i];}}}// 组合结果let result = sign + chineseInteger + chineseDecimal;if (!chineseInteger && !chineseDecimal) {result = cnNums[0] + cnIntLast + cnInteger;} else if (!chineseDecimal) {result += cnInteger;}return result;}
样式中通过定位,来实现input上面内容的展示
<style lang="scss" scoped>.moneyInputBox{position: relative;input{width: 100%;padding: 0 10rpx !important;box-sizing: border-box !important;border: 1rpx solid #dadbde;height: 62rpx !important;line-height: 42rpx!important;border-radius: 4px;}.bigNumBox{position: absolute;bottom: 76rpx;width:auto;background: rgba(0,0,0,.5);padding:10rpx;color:#fff;border-radius: 20rpx;border:1rpx solid #dadbde;}}
</style>

5)将我们当前的组件,用watch监听+emit发送的方法,实现数据的双向绑定,可以在父级用v-model来绑定内容

js具体配置:
<script setup>import { ref, watch, defineProps, defineEmits } from 'vue'const props = defineProps({modelValue: {type: [Number, String],default: 0}})const emit = defineEmits(['update:modelValue'])// 监听外部传入的modelValue变化watch(() => props.modelValue, (newVal) => {if (newVal !== rawValue.value) {rawValue.value = parseFloat(newVal) || 0displayValue.value = formatDisplay(rawValue.value)bigNumCont.value = amountToChinese(rawValue.value)}}, { immediate: true })  </script>
父级调用:
<moneyInput v-model="moneyNum"></moneyInput><script setup>const moneyNum = ref(100)

封装代码源码  moneyInput.vue

<template><view class="moneyInputBox"><inputv-model="displayValue"@input="handleInput"@blur="handleBlur"@focus="handleFocus"placeholder="请输入金额"/><view v-if="showBigNum" class="bigNumBox">{{bigNumCont}}</view></view>
</template><script setup>import { ref, watch, defineProps, defineEmits } from 'vue'const props = defineProps({modelValue: {type: [Number, String],default: 0}})const emit = defineEmits(['update:modelValue'])const displayValue = ref('')const rawValue = ref(0)const maxFloatNum = ref(2)const maxNum = ref(100000000000)const showBigNum = ref(false)const bigNumCont = ref('')// 格式化显示值(添加千分位)const formatDisplay = (value) => {const num = parseFloat(value || 0)return num.toFixed(maxFloatNum.value).replace(/\B(?=(\d{3})+(?!\d))/g, ',')}// 处理输入变化const handleInput = (e) => {let val = e.detail.valueif(!val) return ''let value = val.toString().replace(/[^\d.]/g, '')if (value.length > 1 && value.startsWith('0')) {value = value.substring(1)}const min = 0const max = maxNum.value// 确保只有一个点const parts = value.split('.')if (parts.length > 2) {value = parts[0] + '.' + parts.slice(1).join('')}// 限制小数点后两位if (parts.length === maxFloatNum.value) {value = parts[0] + '.' + parts[1].slice(0, maxFloatNum.value)}// 转换为数字const numValue = parseFloat(value || 0)// 检查范围if (numValue > max) {value = max.toString()} else if (numValue < min) {value = min.toString()}rawValue.value = numValuedisplayValue.value = valuebigNumCont.value = amountToChinese(rawValue.value)emit('update:modelValue', rawValue.value)}// 处理失去焦点const handleBlur = () => {showBigNum.value = falsedisplayValue.value = formatDisplay(rawValue.value)bigNumCont.value = amountToChinese(rawValue.value)}// 处理获取焦点const handleFocus = () => {showBigNum.value = truedisplayValue.value = rawValue.value.toString()bigNumCont.value = amountToChinese(rawValue.value)}const amountToChinese = (num)=> {const cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']const cnIntRadice = ['', '拾', '佰', '仟']const cnIntUnits = ['', '万', '亿', '兆']const cnDecUnits = ['角', '分', '毫', '厘']const cnInteger = '整'const cnIntLast = '元'if(num > maxNum.value){return '-'}// 处理负数let sign = '';if (num < 0) {sign = '负';num = Math.abs(num);}// 分离整数和小数部分let numStr = num.toString();let integerStr = '';let decimalStr = '';if (numStr.indexOf('.') !== -1) {const parts = numStr.split('.');integerStr = parts[0];decimalStr = parts[1].substring(0, 4); // 最多支持4位小数} else {integerStr = numStr;}// 处理整数部分let chineseInteger = '';if (parseInt(integerStr, 10) > 0) {let zeroCount = 0;const intLen = integerStr.length;for (let i = 0; i < intLen; i++) {const n = integerStr.charAt(i);const p = intLen - i - 1;const q = p / 4;const m = p % 4;if (n === '0') {zeroCount++;} else {if (zeroCount > 0) {chineseInteger += cnNums[0];}zeroCount = 0;chineseInteger += cnNums[parseInt(n)] + cnIntRadice[m];}if (m === 0 && zeroCount < 4) {chineseInteger += cnIntUnits[q];}}chineseInteger += cnIntLast;}// 处理小数部分let chineseDecimal = '';if (decimalStr) {for (let i = 0; i < decimalStr.length; i++) {const n = decimalStr.charAt(i);if (n !== '0') {chineseDecimal += cnNums[parseInt(n)] + cnDecUnits[i];}}}// 组合结果let result = sign + chineseInteger + chineseDecimal;if (!chineseInteger && !chineseDecimal) {result = cnNums[0] + cnIntLast + cnInteger;} else if (!chineseDecimal) {result += cnInteger;}return result;}// 监听外部传入的modelValue变化watch(() => props.modelValue, (newVal) => {if (newVal !== rawValue.value) {rawValue.value = parseFloat(newVal) || 0displayValue.value = formatDisplay(rawValue.value)bigNumCont.value = amountToChinese(rawValue.value)}}, { immediate: true })
</script><style lang="scss" scoped>.moneyInputBox{position: relative;input{width: 100%;padding: 0 10rpx !important;box-sizing: border-box !important;border: 1rpx solid #dadbde;height: 62rpx !important;line-height: 42rpx!important;border-radius: 4px;}.bigNumBox{position: absolute;bottom: 76rpx;width:auto;background: rgba(0,0,0,.5);padding:10rpx;color:#fff;border-radius: 20rpx;border:1rpx solid #dadbde;}}
</style>

http://www.dtcms.com/a/305969.html

相关文章:

  • 《CLIP改进工作串讲》论文精读笔记
  • uniapp使用谷歌地图获取位置
  • uniapp实现微信小程序导航功能
  • 从单机到分布式:Redis如何成为架构升级的胜负手
  • 问题1:uniapp在pages样式穿刺没有问题,在components组件中样式穿刺小程序不起效果
  • Oracle迁移PostgreSQL隐式类型转换配置指南
  • FPGA实现CameraLink视频解码转SRIO与DSP交互,FPGA+DSP多核异构图像处理架构,提供2套工程源码和技术支持
  • Windows Server 2019 查询最近7天远程登录源 IP 地址(含 RDP 和网络登录)
  • 【OD机试题解法笔记】符号运算
  • AWS Blockchain Templates:快速部署企业级区块链网络的终极解决方案
  • Keil-C51 与 Keil -ARM 项目工程兼容的方法
  • leetcode热题——搜索二维矩阵Ⅱ
  • Syzkaller实战教程2:运行环境配置+实例运行
  • 多模通信·数据采集:AORO P9000U三防平板带来定制化解决方案
  • Rust × Elasticsearch官方 `elasticsearch` crate 上手指南
  • Hyperchain 的分级权限体系如何应对潜在的安全威胁和攻击?
  • 龙虎榜——20250730
  • 2018 年 NOI 最后一题题解
  • 学会使用golang zap日志库
  • 【MATLAB】(一)简介
  • 字节跳动“扣子”(Coze)开源:AI智能体生态的技术革命
  • ansible 版本升级
  • colima 修改镜像源为国内源
  • mybatis-入门
  • 笔记本电脑开机慢系统启动慢怎么办?【图文详解】win7/10/11开机慢
  • [leetcode] 反转字符串中的单词
  • 【JVM篇10】:三种垃圾回收算法对比详解
  • CMS框架漏洞
  • QT笔记--》QMenu
  • Apache FOP实践——pdf模板引擎