taro-material
Version:
Mini Program components that implement Google's Material Design.
180 lines (163 loc) • 5.01 kB
JavaScript
import Nerv from "nervjs";
import Taro from "@tarojs/taro-h5";
import { View, Input, Text } from '@tarojs/components';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import _toString from 'lodash/toString';
import AtComponent from "../../common/component";
import { initTestEnv } from "../../common/utils";
// 实现两数相加并保留小数点后最短尾数
function addNum(num1, num2) {
let sq1, sq2;
try {
sq1 = _toString(num1).split('.')[1].length;
} catch (e) {
sq1 = 0;
}
try {
sq2 = _toString(num2).split('.')[1].length;
} catch (e) {
sq2 = 0;
}
const m = Math.pow(10, Math.max(sq1, sq2));
return (Math.round(num1 * m) + Math.round(num2 * m)) / m;
}
// 格式化数字,处理01变成1,并且不处理1. 这种情况
function parseValue(num) {
if (num === '') return '0';
const numStr = _toString(num);
if (numStr.indexOf('0') === 0 && numStr.indexOf('.') === -1) {
// 处理01变成1,并且不处理1.
return _toString(parseFloat(num));
}
return _toString(num);
}
initTestEnv();
class AtInputNumber extends AtComponent {
handleClick(clickType) {
const { disabled, value, min, max, step } = this.props;
const lowThanMin = clickType === 'minus' && value <= min;
const overThanMax = clickType === 'plus' && value >= max;
if (lowThanMin || overThanMax || disabled) {
const deltaValue = clickType === 'minus' ? -step : step;
const errorValue = addNum(value, deltaValue);
if (disabled) {
this.handleError({
type: 'DISABLED',
errorValue
});
} else {
this.handleError({
type: lowThanMin ? 'LOW' : 'OVER',
errorValue
});
}
return;
}
const deltaValue = clickType === 'minus' ? -step : step;
let newValue = addNum(value, deltaValue);
newValue = this.handleValue(newValue);
this.props.onChange(newValue);
}
handleValue = value => {
const { max, min } = this.props;
let resultValue = value === '' ? min : value;
// 此处不能使用 Math.max,会是字符串变数字,并丢失 .
if (resultValue > max) {
resultValue = max;
this.handleError({
type: 'OVER',
errorValue: resultValue
});
}
if (resultValue < min) {
resultValue = min;
this.handleError({
type: 'LOW',
errorValue: resultValue
});
}
resultValue = parseValue(resultValue);
return resultValue;
};
handleInput = (e, ...arg) => {
const { value } = e.target;
const { disabled } = this.props;
if (disabled) return;
const newValue = this.handleValue(value);
this.props.onChange(newValue, e, ...arg);
return newValue;
};
handleBlur = (...arg) => this.props.onBlur(...arg);
handleError = errorValue => {
if (!this.props.onErrorInput) {
return;
}
this.props.onErrorInput(errorValue);
};
render() {
const {
customStyle,
className,
width,
disabled,
value,
type,
min,
max,
size
} = this.props;
const inputStyle = {
width: width ? `${Taro.pxTransform(width)}` : ''
};
const inputValue = this.handleValue(value);
const rootCls = classNames('at-input-number', {
'at-input-number--lg': size
}, className);
const minusBtnCls = classNames('at-input-number__btn', {
'at-input-number--disabled': inputValue <= min || disabled
});
const plusBtnCls = classNames('at-input-number__btn', {
'at-input-number--disabled': inputValue >= max || disabled
});
return <View className={rootCls} style={customStyle}>
<View className={minusBtnCls} onClick={this.handleClick.bind(this, 'minus')}>
<Text className="at-icon at-icon-subtract at-input-number__btn-subtract"></Text>
</View>
<Input className="at-input-number__input" style={inputStyle} type={type} value={inputValue} disabled={disabled} onInput={this.handleInput} onBlur={this.handleBlur} />
<View className={plusBtnCls} onClick={this.handleClick.bind(this, 'plus')}>
<Text className="at-icon at-icon-add at-input-number__btn-add"></Text>
</View>
</View>;
}
}
AtInputNumber.defaultProps = {
customStyle: '',
className: '',
disabled: false,
value: 1,
type: 'number',
width: 0,
min: 0,
max: 100,
step: 1,
size: '',
onChange: () => {},
onBlur: () => {}
};
AtInputNumber.propTypes = {
customStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
className: PropTypes.oneOfType([PropTypes.array, PropTypes.string]),
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
type: PropTypes.oneOf(['number', 'digit']),
disabled: PropTypes.bool,
width: PropTypes.number,
min: PropTypes.number,
max: PropTypes.number,
step: PropTypes.number,
size: PropTypes.string,
onChange: PropTypes.func,
onBlur: PropTypes.func,
onErrorInput: PropTypes.func
};
export default AtInputNumber;