InputNumber组件
数字输入框
使用
var props={ autoFocus,// 初始化是否获得焦点 size,// 尺寸 name readonly className disabled prefixCls: 'rc-input-number',// 类前缀 max: Infinity,// 最大值 min: -Infinity,// 最小值 step: 1,// 步长,"e-"或含"."将value精确到保留小数点后几位 style: {},// 样式 defaultValue: '', onChange: noop,// input失去焦点时或上下箭头点击时,更新state.inputValue触发执行函数 onKeyDown: noop,// input输入框按键时触发执行函数 onFocus: noop,// input输入框获得焦点时触发执行函数 onBlur: noop// input输入框失去焦点时触发执行事件 }; <InputNumber {...props}>
源码
rc-input-number模块,构成组件核心代码,被调用时再设置样式主题。
'use strict'; // 浅拷贝 var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var _react = require('react'); var _react2 = _interopRequireDefault(_react); // classnames函数参数为字符串或数值时,拼接样式并返回;为对象时,拼接键并返回 // 为数组时,根据数组元素项的不同获取样式 var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames); function noop() {} function preventDefault(e) { e.preventDefault(); } var InputNumber = _react2['default'].createClass({ displayName: 'InputNumber', propTypes: { onChange: _react2['default'].PropTypes.func, onKeyDown: _react2['default'].PropTypes.func, onFocus: _react2['default'].PropTypes.func, onBlur: _react2['default'].PropTypes.func, max: _react2['default'].PropTypes.number, min: _react2['default'].PropTypes.number, step: _react2['default'].PropTypes.oneOfType([_react2['default'].PropTypes.number, _react2['default'].PropTypes.string]) }, getDefaultProps: function getDefaultProps() { return { // autoFocus,// 初始化是否获得焦点 // name // readonly // className // disabled prefixCls: 'rc-input-number',// 类前缀 max: Infinity,// 最大值 min: -Infinity,// 最小值 step: 1,// 步长,"e-"或含"."将value精确到保留小数点后几位 style: {},// 样式 defaultValue: '', onChange: noop,// input失去焦点时或上下箭头点击时,更新state.inputValue触发执行函数 onKeyDown: noop,// input输入框按键时触发执行函数 onFocus: noop,// input输入框获得焦点时触发执行函数 onBlur: noop// input输入框失去焦点时触发执行事件 }; }, getInitialState: function getInitialState() { var value = undefined; var props = this.props; if ('value' in props) { value = props.value; } else { value = props.defaultValue; } value = this.toPrecisionAsStep(value); return { inputValue: value,// 根据用户操作的实时更新值??? value: value,// 用于重设时的初始值??? focused: props.autoFocus// 初始化是否获得焦点 }; }, componentDidMount: function componentDidMount() { this.componentDidUpdate(); }, // value根据props.step设置重新调整为保留小数点后几位格式 componentWillReceiveProps: function componentWillReceiveProps(nextProps) { if ('value' in nextProps) { var value = this.toPrecisionAsStep(nextProps.value); this.setState({ inputValue: value, value: value }); } }, componentDidUpdate: function componentDidUpdate() { // 初始化获得焦点 if (this.state.focused && document.activeElement !== this.refs.input) { this.refs.input.focus(); } }, // 监听input元素的change事件,重设state.inputValue onChange: function onChange(event) { this.setInputValue(event.target.value.trim()); }, // 监听input元素按键事件,触发props.onKeyDown执行 onKeyDown: function onKeyDown(e) { var _props; if (e.keyCode === 38) { this.up(e); } else if (e.keyCode === 40) { this.down(e); } for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } (_props = this.props).onKeyDown.apply(_props, [e].concat(args)); }, // 获得焦点,并触发props.onFocus函数执行 onFocus: function onFocus() { var _props2; this.setState({ focused: true }); (_props2 = this.props).onFocus.apply(_props2, arguments); }, // 失去焦点,将输入框重设为有效值,并触发props.onBlur函数执行 onBlur: function onBlur(e) { var _props3; this.setState({ focused: false }); var value = this.getCurrentValidValue(e.target.value.trim()); this.setValue(value); for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { args[_key2 - 1] = arguments[_key2]; } (_props3 = this.props).onBlur.apply(_props3, [e].concat(args)); }, // 上下按钮点击时执行,将输入框的值重设为有效值 onStepMouseDown: function onStepMouseDown(e) { e.preventDefault(); var value = this.getCurrentValidValue(this.state.inputValue); this.setState({ value: value }); }, // 获取当前的有效值,根据props.min、props.max作调整,重设小数点后几位 getCurrentValidValue: function getCurrentValidValue(value) { var val = value; var props = this.props; if (val === '') { val = ''; } else if (!isNaN(val)) { val = Number(val); if (val < props.min) { val = props.min; } if (val > props.max) { val = props.max; } } else { val = this.state.value; } return this.toPrecisionAsStep(val); }, // 没有state.value时,添加state.value,更新state.inputValue // setValue方法在输入框失去焦点或上下按钮点击时调用 setValue: function setValue(v) { if (!('value' in this.props)) { this.setState({ value: v, inputValue: v }); } var newValue = isNaN(v) || v === '' ? undefined : v; if (newValue !== this.state.value) { this.props.onChange(newValue); } else { this.setState({ inputValue: this.state.value }); } }, // 重设state.inputValue setInputValue: function setInputValue(v) { this.setState({ inputValue: v }); }, // 保留小数点后几位 getPrecision: function getPrecision() { var props = this.props; var stepString = props.step.toString(); if (stepString.indexOf('e-') >= 0) { return parseInt(stepString.slice(stepString.indexOf('e-') + 1), 10); } var precision = 0; if (stepString.indexOf('.') >= 0) { precision = stepString.length - stepString.indexOf('.') - 1; } return precision; }, // 小数点后保留n位,精确计算因子precisionFactor就是10的n次方,便于计算,不需要处理小数 getPrecisionFactor: function getPrecisionFactor() { var precision = this.getPrecision(); return Math.pow(10, precision); }, // num调整为保留小数点后几位形式 toPrecisionAsStep: function toPrecisionAsStep(num) { if (isNaN(num) || num === '') { return num; } var precision = this.getPrecision(); return Number(Number(num).toFixed(Math.abs(precision))); }, // 加一个步长 upStep: function upStep(val) { var _props4 = this.props; var step = _props4.step; var min = _props4.min; var precisionFactor = this.getPrecisionFactor(); var result = undefined; if (typeof val === 'number') { result = (precisionFactor * val + precisionFactor * step) / precisionFactor; } else { result = min === -Infinity ? step : min; } return this.toPrecisionAsStep(result); }, // 减一个步长 downStep: function downStep(val) { var _props5 = this.props; var step = _props5.step; var min = _props5.min; var precisionFactor = this.getPrecisionFactor(); var result = undefined; if (typeof val === 'number') { result = (precisionFactor * val - precisionFactor * step) / precisionFactor; } else { result = min === -Infinity ? -step : min; } return this.toPrecisionAsStep(result); }, // 加或减一个步长,并重新绘制组件 step: function step(type, e) { if (e) { e.preventDefault(); } var props = this.props; if (props.disabled) { return; } var value = this.state.value; if (isNaN(value)) { return; } var val = this[type + 'Step'](value); if (val > props.max || val < props.min) { return; } this.setValue(val); this.setState({ focused: true }); }, // 下箭头点中时触发,减一个步长,并重新绘制组件 down: function down(e) { this.step('down', e); }, // 上箭头点中时触发,加一个步长,并重新绘制组件 up: function up(e) { this.step('up', e); }, // 获得焦点 focus: function focus() { this.refs.input.focus(); }, render: function render() { var _classNames; var props = _extends({}, this.props); var prefixCls = props.prefixCls; var classes = (0, _classnames2['default'])((_classNames = {}, _defineProperty(_classNames, prefixCls, true), _defineProperty(_classNames, props.className, !!props.className), _defineProperty(_classNames, prefixCls + '-disabled', props.disabled), _defineProperty(_classNames, prefixCls + '-focused', this.state.focused), _classNames) ); var upDisabledClass = ''; var downDisabledClass = ''; var value = this.state.value; if (!isNaN(value)) { var val = Number(value); if (val >= props.max) { upDisabledClass = prefixCls + '-handler-up-disabled'; } if (val <= props.min) { downDisabledClass = prefixCls + '-handler-down-disabled'; } } else { upDisabledClass = prefixCls + '-handler-up-disabled'; downDisabledClass = prefixCls + '-handler-down-disabled'; } // focus state, show input value // unfocus state, show valid value var inputDisplayValue = undefined; if (this.state.focused) { inputDisplayValue = this.state.inputValue; } else { inputDisplayValue = this.state.value; } if (inputDisplayValue === undefined) { inputDisplayValue = ''; } // input元素必须是可控组件或不可控组件 // 前者使用props.value设置值,可以使用setState作更改 // 后者使用props.defaultValue设置值,不可使用setState作更改 delete props.defaultValue; // https://fb.me/react-unknown-prop delete props.prefixCls; return _react2['default'].createElement( 'div', { className: classes, style: props.style }, _react2['default'].createElement( 'div', { className: prefixCls + '-handler-wrap' }, _react2['default'].createElement( 'a', { unselectable: 'unselectable', ref: 'up', onClick: upDisabledClass ? noop : this.up, onMouseDown: this.onStepMouseDown, className: prefixCls + '-handler ' + prefixCls + '-handler-up ' + upDisabledClass }, _react2['default'].createElement( 'span', { unselectable: 'unselectable', className: prefixCls + '-handler-up-inner', onClick: preventDefault } ) ), _react2['default'].createElement( 'a', { unselectable: 'unselectable', ref: 'down', onMouseDown: this.onStepMouseDown, onClick: downDisabledClass ? noop : this.down, className: prefixCls + '-handler ' + prefixCls + '-handler-down ' + downDisabledClass }, _react2['default'].createElement( 'span', { unselectable: 'unselectable', className: prefixCls + '-handler-down-inner', onClick: preventDefault } ) ) ), _react2['default'].createElement( 'div', { className: prefixCls + '-input-wrap' }, _react2['default'].createElement('input', _extends({}, props, { style: null, className: prefixCls + '-input', autoComplete: 'off', onFocus: this.onFocus, onBlur: this.onBlur, onKeyDown: this.onKeyDown, autoFocus: props.autoFocus, readOnly: props.readOnly, disabled: props.disabled, max: props.max, min: props.min, name: props.name, onChange: this.onChange, ref: 'input',// this.refs.input指向input输入框 value: inputDisplayValue })) ) ); } }); module.exports = InputNumber;
antd-InputNumber.js
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); // 浅拷贝 var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _react = require('react'); var _react2 = _interopRequireDefault(_react); // classnames函数参数为字符串或数值时,拼接样式并返回;为对象时,拼接键并返回 // 为数组时,根据数组元素项的不同获取样式 var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames); var _rcInputNumber = require('rc-input-number'); var _rcInputNumber2 = _interopRequireDefault(_rcInputNumber); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } // 拷贝obj对象,但不拷贝keys中包含的键 function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /*var props={ autoFocus,// 初始化是否获得焦点 size,// 尺寸 name readonly className disabled prefixCls: 'rc-input-number',// 类前缀 max: Infinity,// 最大值 min: -Infinity,// 最小值 step: 1,// 步长,"e-"或含"."将value精确到保留小数点后几位 style: {},// 样式 defaultValue: '', onChange: noop,// input失去焦点时或上下箭头点击时,更新state.inputValue触发执行函数 onKeyDown: noop,// input输入框按键时触发执行函数 onFocus: noop,// input输入框获得焦点时触发执行函数 onBlur: noop// input输入框失去焦点时触发执行事件 }; <InputNumber {...props}>*/ exports.default = _react2.default.createClass({ displayName: 'input-number', getDefaultProps: function getDefaultProps() { return { prefixCls: 'ant-input-number', step: 1 }; }, render: function render() { var _props = this.props; var className = _props.className; var size = _props.size; var other = _objectWithoutProperties(_props, ['className', 'size']); var inputNumberClass = (0, _classnames2.default)(_defineProperty({ 'ant-input-number-lg': size === 'large', 'ant-input-number-sm': size === 'small' }, className, !!className)); return _react2.default.createElement(_rcInputNumber2.default, _extends({ className: inputNumberClass }, other)); } }); module.exports = exports['default'];