InputNumber源码

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'];

猜你喜欢

转载自schifred.iteye.com/blog/2350782
今日推荐