@ttk/component
Version:
ttk组件库
666 lines (600 loc) • 24.1 kB
JavaScript
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import classNames from 'classnames'
import { Input } from 'antd'
import { number as utilsNumber } from '@ttk/utils'
import isequal from 'lodash.isequal'
export default class InputNumberComponent extends Component {
state = {
oldValue: "",
value: "",
max: Infinity,
min: -Infinity,
format: "",
interceptTab: false,
regex: ""
}
constructor(props) {
super(props)
this.state = this.calculateState(props)
}
componentWillReceiveProps(nextProps) {
if (this.props.customAttribute) { //期初余额 自定义的一个属性 为了重置超过限制的数据为初始数据
if (this.props.customAttribute !== nextProps.customAttribute) {
this.setState(this.calculateState(nextProps))
}
}
if (this.props.value !== nextProps.value) {
this.setState(this.calculateState(nextProps))
}
}
assitShouldComponent = (target) => {
let obj = {}
for (const [key, value] of Object.entries(target)) {
if (typeof (value) != 'function') {
obj[key] = value
}
}
return obj
}
shouldComponentUpdate(nextProps, nextState) {
return !(isequal(this.assitShouldComponent(this.props), this.assitShouldComponent(nextProps)) && isequal(this.state, nextState))
}
calculateState(props) {
let data = {}
if (props.value !== undefined) {
data.value = props.value + ''
data.oldValue = data.value
}
else {
data.value = ''
data.oldValue = data.value
}
if (props.min !== undefined && props.min !== null && props.min !== '' && !isNaN(props.min))
data.min = props.min
if (props.max !== undefined && props.max !== null && props.max !== '' && !isNaN(props.max))
data.max = props.max
if (props.format)
data.format = props.format
if (props.precision || props.precision == 0) {
data.precision = props.precision || 0
}
if (props.interceptTab) {
data.interceptTab = props.interceptTab
}
if (props.regex) {
data.regex = props.regex
} else {
data.regex = /^-?(0|[1-9][0-9]*)(\.[0-9]*)?$/
}
return data
}
getCurrentValidValue(value) {
let val = value
const props = this.props
if (val === '') {
return ''
} else if (!this.isNotCompleteNumber(val)) {
val = Number(val)
if (val < this.state.min) {
return this.state.min
}
if (val > this.state.max) {
return this.state.max
}
} else {
return this.state.value
}
return value
}
/**
* 转换为数字
* @param {[type]} num [description]
* @return {[type]} [description]
*/
toNumber(num) {
if (this.isNotCompleteNumber(num)) {
return num
}
return Number(num)
}
/**
* 判断是否非完整数字
* @param {[type]} num [description]
* @return {Boolean} [description]
*/
isNotCompleteNumber(num) {
return (
isNaN(num) ||
num === '' ||
num.toString().indexOf('.') === num.toString().length - 1
)
}
/**
* 根据精度转换值
* @param {[type]} num [description]
* @return {[type]} [description]
*/
toPrecisionAsStep(num) {
//非完整数字直接返回, NaN,'',3444.
if (this.isNotCompleteNumber(num) || num === '') {
return num
}
//获取精度
const precision = this.state.precision
//精度非0的数字,转换
if (precision) {
return Number(num).toFixed(precision)
}
return num.toString()
}
/**
* 获取最大精度
* @param {[type]} currentValue [description]
* @return {[type]} [description]
*/
getMaxPrecision(currentValue) {
const { step } = this.props
let stepPrecision = this.getPrecision(currentValue)
//存在step取step的精度,step的值例如0.0001
if (step)
stepPrecision = this.getPrecision(step)
return stepPrecision
}
/**
* 获取精度
* @param {[type]} value [description]
* @return {[type]} [description]
*/
getPrecision(value) {
const valueString = value.toString()
//取e-后字符转换成int,e-10=>10
if (valueString.indexOf('e-') >= 0) {
return parseInt(valueString.slice(valueString.indexOf('e-') + 1), 10)
}
let precision = 0;
//取小数点后字符长度0.0001=>4
if (valueString.indexOf('.') >= 0) {
precision = valueString.length - valueString.indexOf('.') - 1
}
//否则0
return precision
}
toFixedLocal(value, precision) {
let ret = value
if (value && value.toString().indexOf('.') > -1) {
if (value.toString().split('.')[1].length > precision) {
if (!isNaN(value)) {
//以下有问题,类似1.255这样的,四舍五入后,变成了1.25,调整成新的
// ret = Math.round(value * Math.pow(10, precision) / Math.pow(10, precision))
ret = Math.round(Math.abs(value) + 'e' + precision) / Math.pow(10, precision)
ret = value < 0 ? -ret : ret
} else {
ret = 0
}
}
}
return ret
}
onChange(e) {
let value
if (e.target.validity) {
value = (e.target.validity.valid) ? e.target.value : this.state.value
} else {
value = e.target.value
}
if (value.trim() == '-.') value = 0
const regExp = this.getRegExp()
let isFullAngle = value.match(/[\uff00-\uffff]/g)
if (isFullAngle && isFullAngle.length > 0) {//全角输入法转换为半角输入法
var tmp = "";
for (var i = 0; i < value.length; i++) {
if (value.charCodeAt(i) == 12288) {
tmp += String.fromCharCode(value.charCodeAt(i) - 12256);
continue;
}
if (value.charCodeAt(i) > 65280 && value.charCodeAt(i) < 65375) {
tmp += String.fromCharCode(value.charCodeAt(i) - 65248);
}
else {
tmp += String.fromCharCode(value.charCodeAt(i));
}
}
value = tmp
}
if (value &&
value.toString().length > 1) {
//copyPaste 加个属性缩小一下范围
if (utilsNumber.clearThousPos(value, true) &&
this.props.copyPaste &&
value.toString().length - value.toString().indexOf('.') >= this.props.precision) {
//复制粘贴 四舍五入
value = `${this.toFixedLocal(value, this.props.precision)}`
} else if (value.toString().substr(value.toString().length - 1, 1) != '.' &&
!regExp.test(utilsNumber.clearThousPos(value, true))) {
//手动录入
// edge浏览器微软拼音中文输入法下,小数位数控制不住的问题处理
if (e.preventDefault)
e.preventDefault()
if (e.stopPropagation)
e.stopPropagation()
return
}
}
//当为小数正则表达式时,不进行小数点正则检查
if (regExp.test('0.0') && e.target.value && e.target.value != '' && e.target.value.indexOf('.') > -1) {
if (typeof this.props.maxValue == 'number' && !isNaN(Number(value)) && this.props.maxValue < Number(value)) {
value = this.props.maxValue
}
if (this.props.maxValue == 0 && !isNaN(Number(value)) && 0 < Number(value)) {
value = 0
}
if (typeof this.props.maxValue == 'number' && !isNaN(Number(value)) && this.props.minValue > Number(value)) {
value = this.props.minValue
}
if (this.props.minValue == 0 && !isNaN(Number(value)) && 0 > Number(value)) {
value = 0
}
this.setState({ value })
if (this.props.timeout) {
let keyRandom = Math.floor(Math.random() * 10000000)
this.keyRandom = keyRandom
clearTimeout(this.time)
this.time = setTimeout(() => {
if (keyRandom == this.keyRandom) {
this.state.oldValue != value && this.props.onChange && this.props.onChange(value)
}
}, 100)
} else {
this.state.oldValue != value && this.props.onChange && this.props.onChange(value)
}
}
//是数字或者是空或者是-
if ((!isNaN(utilsNumber.clearThousPos(value, true)) && regExp.test(utilsNumber.clearThousPos(value))) || value === '' || value === '-' || value == '=') {
if (typeof this.props.maxValue == 'number' && !isNaN(Number(value)) && this.props.maxValue < Number(value)) {
value = this.props.maxValue
}
if (this.props.maxValue == 0 && !isNaN(Number(value)) && 0 < Number(value)) {
value = 0
}
if (typeof this.props.maxValue == 'number' && !isNaN(Number(value)) && this.props.minValue > Number(value)) {
value = this.props.minValue
}
if (this.props.minValue == 0 && !isNaN(Number(value)) && 0 > Number(value)) {
value = 0
}
this.setState({ value })
if (this.props.timeout) {
let keyRandom = Math.floor(Math.random() * 10000000)
this.keyRandom = keyRandom
clearTimeout(this.time)
this.time = setTimeout(() => {
if (keyRandom == this.keyRandom) {
if (this.state.oldValue == '' && value == '-') {
console.log('keyRandom:' + this.state.oldValue + " newValue:" + value)
value = ''
}
this.state.oldValue != value && this.props.onChange && this.props.onChange(value)
}
}, 100)
} else {
this.state.oldValue != value && this.props.onChange && this.props.onChange(value)
}
}
}
getStep(str) {
let strAfterPoint = (str + '').split('.')[1]
return strAfterPoint && strAfterPoint.length ? strAfterPoint.length : 0
}
onBlur() {
let value = this.state.value
//最后一个字符是.或者-那么去掉
if (value && (value.charAt(value.length - 1) === '.' || value === '-')) {
value = value.slice(0, -1)
value = this.getCurrentValidValue(value)
value = this.toPrecisionAsStep(this.toNumber(value))
this.setState({
value: value + ''
});
this.state.oldValue != value && this.props.onChange && this.props.onChange(value, this.toPrecisionAsStep(this.toNumber(value)));
}
if (value == '' && this.props.nullToZero) {
value = 0
}
value = this.getCurrentValidValue(value)
value = this.toPrecisionAsStep(this.toNumber(value))
this.setState({
value: value + ''
});
if (this.props.executeBlur) {
/**
* 业务,填制凭证金额由于ONCHANGE事件,导致oldvalue与value永远相等,onblur事件一直执行
*/
this.props.onBlur && this.props.onBlur(value)
}
else {
this.state.oldValue != value && this.props.onBlur && this.props.onBlur(value)
}
}
onKeyDown = (e) => {
if (e.key === 'Enter' || e.keyCode == 13 || e.keyCode == 108 || e.keyCode == 9) { //e.keyCode == 9 不支持tab键,因为如果阻止了事件外抛,select的选择项键盘选中无法生效
if (this.props.onEndEdit) {
this.props.onEndEdit()
if (this.props.interceptTab) {
if (e.keyCode == 9) {
if (e.preventDefault)
e.preventDefault()
if (e.stopPropagation)
e.stopPropagation()
}
}
return
}
}
//空格和等号,这两个对于凭证有特殊含义的快捷键
if (e.key === ' ' || e.keyCode == 32 || e.key === '=' || e.keyCode == 187 ||
(e.target.value && (e.key === '-' || e.keyCode == 189 || e.keyCode == 109)) ||
(e.key === 'Process' && e.keyCode === 229)
) {
// 解决微软拼音中文状态下无法录入金额的问题
if (e.key === 'Process' && e.keyCode === 229) {
if (e.preventDefault)
e.preventDefault()
if (e.stopPropagation)
e.stopPropagation()
return
} else {
if (this.props.onShortcutKey) {
this.props.onShortcutKey(e)
if (e.preventDefault)
e.preventDefault()
if (e.stopPropagation)
e.stopPropagation()
return
}
}
}
if (e.type !== 'keydown' ||
e.keyCode == 8 ||
e.keyCode == 46 ||
e.keyCode == 27 ||
e.keyCode == 9 ||
e.keyCode == 37 ||
e.keyCode == 39 ||
e.keyCode == 38 ||
e.keyCode == 40 ||
e.key === 'Enter' ||
e.keyCode == 13 ||
e.keyCode == 108 ||
(e.ctrlKey)) {
//this.props.onEventKeyDown && this.props.onEventKeyDown(e)
//this.props.onKeyDown && this.props.onKeyDown(e)
return
}
//解极品五笔输入法下,新增凭证中无法输入数字的问题
if (e.keyCode == '229') {
// COMMENT TTK-2229 TTK-2242 解决该问题(IE下微软中文时无法录入数字) 故先注释掉以下四行
// if (e.preventDefault)
// e.preventDefault()
// if (e.stopPropagation)
// e.stopPropagation()
return
}
// 获取光标当前位置
let cursorPosition = this.getCursorPosition(e.target)//utils.dom && utils.dom.getCursorPosition(e.target)
let regExp = this.getRegExp()
//IE 、IE8兼容处理
let selectedText = this.getSelection(),
checkText, keyCode
//Chrome中小数点的ascii码是110(小键盘)、190(大键盘)
if (e.keyCode == 46 || e.keyCode == 110 || e.keyCode == 190) {
// keyCode = 46
//当为小数正则表达式时,不进行小数点正则检查
if (regExp.test('0.0') && e.target.value && e.target.value.indexOf('.') == -1) {
console.log('e.key: ' + e.key)
return
}
//109:小键盘负号的keyCode 189:大键盘负号的keyCode
} else if (e.keyCode == 189 || e.keyCode == 109) {
keyCode = 45
//当为负数正则表达式时,不进行负号正则检查
if (regExp.test('-1') && !e.target.value) {
return
}
} else {
keyCode = e.keyCode
}
let stateValue = this.state.value.toString()
if (selectedText != '') {
stateValue = stateValue.replace(selectedText, '')
}
//将输入的字符插入数字串中
if (stateValue.length == cursorPosition) {
if (regExp.test('-1')) { //为了解决edge和ie下,值有负号不能全选修改的问题
stateValue = stateValue.replace(/-/g, '')
}
checkText = stateValue + this.stringFromCharCode(keyCode)
} else if (cursorPosition == 0) {
if (regExp.test('-1')) {//为了解决edge和ie下,值有负号不能全选修改的问题
stateValue = stateValue.replace(/-/g, '')
}
checkText = this.stringFromCharCode(keyCode) + stateValue
} else {
if (regExp.test('-1')) {//为了解决edge和ie下,值有负号不能全选修改的问题
stateValue = stateValue.replace(/-/g, '')
}
checkText = stateValue.substring(0, cursorPosition) +
this.stringFromCharCode(keyCode) +
stateValue.substring(cursorPosition)
}
//去掉输入值中的逗号
if (checkText) {
if (checkText.indexOf(',') > -1) {
checkText = checkText.replace(/,/g, '')
}
}
// if (!regExp.test(checkText)) {
// if (e.preventDefault)
// e.preventDefault()
// if (e.stopPropagation)
// e.stopPropagation()
// return
// }
if (regExp.test('-1')) {
// 为了解决 360浏览器和谷歌浏览器输入负号无法输入的情况
// if (checkText != '-' && !regExp.test(checkText)) {
if (checkText != '-' && !regExp.test(checkText) && !(checkText && (checkText.toLocaleLowerCase().includes('x') || checkText.toLocaleLowerCase().includes('c') || checkText.toLocaleLowerCase().includes('v')))) {
if (e.preventDefault)
e.preventDefault()
if (e.stopPropagation)
e.stopPropagation()
return
}
} else {
if (!regExp.test(checkText)) {
if (e.preventDefault)
e.preventDefault()
if (e.stopPropagation)
e.stopPropagation()
return
}
}
}
getCursorPosition = (target) => {
var oTxt1 = target;
var cursorPosition = -1;
if (oTxt1.selectionStart != undefined) {//非IE浏览器
cursorPosition = oTxt1.selectionStart;
} else {//IE
var range = document.selection.createRange();
range.moveStart("character", -oTxt1.value.length);
cursorPosition = range.text.length;
}
return cursorPosition
}
/**
* IE:document.selection
* FireFox:window.getSelection()
* window.getSelection()也只有FireFox和Safari支持 selection 对象
*/
getSelection = () => {
if (window.getSelection) {
return window.getSelection().toString()
}
else if (document.getSelection) {
return document.getSelection().toString()
} else if (document.selection) {
return document.selection.createRange().text
}
}
getRegExp() {
let regExp
if (this.props.regex) {
regExp = new RegExp(this.props.regex)
} else {
if (this.props.precision) {
regExp = new RegExp("^(-?[0-9]+)(?:\\.[0-9]{1," + this.props.precision + "})?$")
} else if (this.props.precision == 0) {
regExp = new RegExp(/^(-?[0-9]+)?$/)
} else {
regExp = new RegExp(/^(-?[0-9]+)(?:\.[0-9]{1,12})?$/)
}
}
return regExp
}
handleKeyUp(e) {
let repValue = e.target.value
//[\u4e00-\u9fa5] 中文正则表达式 将中文替换为空,实现Input无法输入中文的功能
if (e.target.value.indexOf('.') != -1) {
repValue = e.target.value.replace('。', '')
}
repValue = repValue.replace(/[\u4e00-\u9fa5]/g, '')
//录入了字母+中文时,字母会被录入
let regExp = this.getRegExp()
//若regex为小数正则,则忽略小数点.
if ((regExp.test('0.0') && e.target.value &&
e.target.value.indexOf(".") == 0 &&
e.target.value != '-.') ||
(regExp.test('-1') && e.target.value == '-') ||
(e.target.value != '-.')) {
if (!regExp.test(e.target.value)) {
if (e.preventDefault)
e.preventDefault()
if (e.stopPropagation)
e.stopPropagation()
return
}
} else {
if (!regExp.test(repValue)) {
repValue = ''
}
}
this.setState({ value: repValue })
this.props.onKeyUp && this.props.onKeyUp(e)
}
stringFromCharCode = (keyCode) => {
let ret = ''
if (keyCode == 96) {
ret = '0'
} else if (keyCode == 97) {
ret = '1'
} else if (keyCode == 98) {
ret = '2'
} else if (keyCode == 99) {
ret = '3'
} else if (keyCode == 100) {
ret = '4'
} else if (keyCode == 101) {
ret = '5'
} else if (keyCode == 102) {
ret = '6'
} else if (keyCode == 103) {
ret = '7'
} else if (keyCode == 104) {
ret = '8'
} else if (keyCode == 105) {
ret = '9'
} else {
ret = String.fromCharCode(keyCode)
}
return ret
}
handleFocus = (e) => {
//获取事件对象 兼容IE8
const eve = e || window
////获取document 对象的引用 兼容IE8
const objEle = eve.target || eve.srcElement
objEle.focus()
let keyRandom = Math.floor(Math.random() * 10000000)
this.keyRandom = keyRandom
clearTimeout(this.time)
this.time = setTimeout(() => {
if (keyRandom == this.keyRandom) {
if (document.activeElement && typeof document.activeElement.select == 'function') {
document.activeElement.select()
} else {
objEle.select()
}
}
}, 10)
this.props.onFocus && this.props.onFocus(e)
}
render() {
let className = classNames({
'mk-input-number': true,
[this.props.className]: !!this.props.className
})
return (
<Input
{...this.props}
autoComplete='off'
className={className}
onChange={this.onChange.bind(this)}
onKeyDown = {this.onKeyDown.bind(this) }
onKeyUp = {this.handleKeyUp.bind(this) }
onFocus = {this.handleFocus.bind(this) }
value = { this.state.value }
onBlur = {this.onBlur.bind(this) }
/>)
}
}