Browse Source

feat: update inputnumber

pull/2502/head
tangjinzhou 4 years ago
parent
commit
93bde3fb67
  1. 2
      antdv-demo
  2. 57
      components/input-number/index.jsx
  3. 12
      components/vc-input-number/src/InputHandler.js
  4. 163
      components/vc-input-number/src/index.js
  5. 77
      components/vc-m-feedback/src/TouchFeedback.jsx
  6. 2
      examples/App.vue
  7. 2
      examples/index.js

2
antdv-demo

@ -1 +1 @@
Subproject commit 6cde2f94ca4a1dbbb260a4436369e2084ff467ed
Subproject commit d680625687a695a9b9a06a131e12f9611a480d5b

57
components/input-number/index.jsx

@ -1,11 +1,11 @@
import { inject } from 'vue';
import PropTypes from '../_util/vue-types';
import { initDefaultProps, getOptionProps, getListeners } from '../_util/props-util';
import { initDefaultProps, getOptionProps } from '../_util/props-util';
import classNames from 'classnames';
import UpOutlined from '@ant-design/icons-vue/UpOutlined';
import DownOutlined from '@ant-design/icons-vue/DownOutlined';
import VcInputNumber from '../vc-input-number/src';
import { ConfigConsumerProps } from '../config-provider';
import Base from '../base';
export const InputNumberProps = {
prefixCls: PropTypes.string,
@ -29,56 +29,59 @@ export const InputNumberProps = {
const InputNumber = {
name: 'AInputNumber',
model: {
prop: 'value',
event: 'change',
},
inheritAttrs: false,
props: initDefaultProps(InputNumberProps, {
step: 1,
}),
inject: {
configProvider: { default: () => ConfigConsumerProps },
setup() {
return {
configProvider: inject('configProvider', ConfigConsumerProps),
};
},
methods: {
saveInputNumber(inputNumberRef) {
this.inputNumberRef = inputNumberRef;
},
focus() {
this.$refs.inputNumberRef.focus();
this.inputNumberRef.focus();
},
blur() {
this.$refs.inputNumberRef.blur();
this.inputNumberRef.blur();
},
},
render() {
const { prefixCls: customizePrefixCls, size, ...others } = getOptionProps(this);
const { prefixCls: customizePrefixCls, size, class: className, ...others } = {
...getOptionProps(this),
...this.$attrs,
};
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('input-number', customizePrefixCls);
const inputNumberClass = classNames({
[`${prefixCls}-lg`]: size === 'large',
[`${prefixCls}-sm`]: size === 'small',
});
const inputNumberClass = classNames(
{
[`${prefixCls}-lg`]: size === 'large',
[`${prefixCls}-sm`]: size === 'small',
},
className,
);
const upIcon = <UpOutlined class={`${prefixCls}-handler-up-inner`} />;
const downIcon = <DownOutlined class={`${prefixCls}-handler-down-inner`} />;
const vcInputNumberprops = {
props: {
prefixCls,
upHandler: upIcon,
downHandler: downIcon,
...others,
},
prefixCls,
upHandler: upIcon,
downHandler: downIcon,
...others,
class: inputNumberClass,
ref: 'inputNumberRef',
on: getListeners(this),
};
return <VcInputNumber {...vcInputNumberprops} />;
return <VcInputNumber {...vcInputNumberprops} ref={this.saveInputNumber} />;
},
};
/* istanbul ignore next */
InputNumber.install = function(Vue) {
Vue.use(Base);
Vue.component(InputNumber.name, InputNumber);
InputNumber.install = function(app) {
app.component(InputNumber.name, InputNumber);
};
export default InputNumber;

12
components/vc-input-number/src/InputHandler.js

@ -1,9 +1,10 @@
import PropTypes from '../../_util/vue-types';
import Touchable from '../../vc-m-feedback';
import { getListeners } from '../../_util/props-util';
import { getSlot } from '../../_util/props-util';
const InputHandler = {
name: 'InputHandler',
inheritAttrs: false,
props: {
prefixCls: PropTypes.string,
disabled: PropTypes.bool,
@ -11,15 +12,12 @@ const InputHandler = {
render() {
const { prefixCls, disabled } = this.$props;
const touchableProps = {
props: {
disabled,
activeClassName: `${prefixCls}-handler-active`,
},
on: getListeners(this),
disabled,
activeClassName: `${prefixCls}-handler-active`,
};
return (
<Touchable {...touchableProps}>
<span>{this.$slots.default}</span>
<span {...this.$attrs}>{getSlot(this)}</span>
</Touchable>
);
},

163
components/vc-input-number/src/index.js

@ -1,7 +1,7 @@
// based on rc-input-number 4.5.5
import PropTypes from '../../_util/vue-types';
import BaseMixin from '../../_util/BaseMixin';
import { initDefaultProps, hasProp, getOptionProps, getListeners } from '../../_util/props-util';
import { initDefaultProps, hasProp, getOptionProps } from '../../_util/props-util';
import classNames from 'classnames';
import KeyCode from '../../_util/KeyCode';
import InputHandler from './InputHandler';
@ -76,15 +76,17 @@ const inputNumberProps = {
title: PropTypes.string,
name: PropTypes.string,
id: PropTypes.string,
type: PropTypes.string,
};
export default {
name: 'VCInputNumber',
mixins: [BaseMixin],
model: {
prop: 'value',
event: 'change',
},
inheritAttrs: false,
// model: {
// prop: 'value',
// event: 'change',
// },
props: initDefaultProps(inputNumberProps, {
focusOnUpDown: true,
useTouch: false,
@ -158,6 +160,7 @@ export default {
typeof nextValue === 'number' &&
nextValue > max
) {
this.$emit('update:value', max);
this.$emit('change', max);
}
if (
@ -166,6 +169,7 @@ export default {
typeof nextValue === 'number' &&
nextValue < min
) {
this.$emit('update:value', min);
this.$emit('change', min);
}
}
@ -179,7 +183,7 @@ export default {
},
methods: {
updatedFunc() {
const inputElem = this.$refs.inputRef;
const inputElem = this.inputRef;
// Restore cursor
try {
// Firefox set the input cursor after it get focused.
@ -270,7 +274,9 @@ export default {
}
this.rawInput = this.parser(this.getValueFromEvent(e));
this.setState({ inputValue: this.rawInput });
this.$emit('change', this.toNumber(this.rawInput)); // valid number or invalid string
const num = this.toNumber(this.rawInput); // valid number or invalid string
this.$emit('update:value', num);
this.$emit('change', num);
},
onFocus(...args) {
this.setState({
@ -285,12 +291,12 @@ export default {
});
const value = this.getCurrentValidValue(this.inputValue);
const newValue = this.setValue(value);
if (this.$listeners.blur) {
const originValue = this.$refs.inputRef.value;
if (this.$attrs.onBlur) {
const originValue = this.inputRef.value;
const inputValue = this.getInputDisplayValue({ focused: false, sValue: newValue });
this.$refs.inputRef.value = inputValue;
this.inputRef.value = inputValue;
this.$emit('blur', ...args);
this.$refs.inputRef.value = originValue;
this.inputRef.value = originValue;
}
},
getCurrentValidValue(value) {
@ -366,6 +372,7 @@ export default {
);
}
if (changed) {
this.$emit('update:value', newValue);
this.$emit('change', newValue);
}
return newValue;
@ -431,7 +438,7 @@ export default {
recordCursorPosition() {
// Record position
try {
const inputElem = this.$refs.inputRef;
const inputElem = this.inputRef;
this.cursorStart = inputElem.selectionStart;
this.cursorEnd = inputElem.selectionEnd;
this.currentValue = inputElem.value;
@ -444,17 +451,12 @@ export default {
}
},
fixCaret(start, end) {
if (
start === undefined ||
end === undefined ||
!this.$refs.inputRef ||
!this.$refs.inputRef.value
) {
if (start === undefined || end === undefined || !this.inputRef || !this.inputRef.value) {
return;
}
try {
const inputElem = this.$refs.inputRef;
const inputElem = this.inputRef;
const currentStart = inputElem.selectionStart;
const currentEnd = inputElem.selectionEnd;
@ -470,7 +472,7 @@ export default {
restoreByAfter(str) {
if (str === undefined) return false;
const fullStr = this.$refs.inputRef.value;
const fullStr = this.inputRef.value;
const index = fullStr.lastIndexOf(str);
if (index === -1) return false;
@ -504,11 +506,11 @@ export default {
});
},
focus() {
this.$refs.inputRef.focus();
this.inputRef.focus();
this.recordCursorPosition();
},
blur() {
this.$refs.inputRef.blur();
this.inputRef.blur();
},
formatWrapper(num) {
// http://2ality.com/2012/03/signedzero.html
@ -621,8 +623,20 @@ export default {
handleInputClick() {
this.$emit('click');
},
saveUp(node) {
this.upHandlerRef = node;
},
saveDown(node) {
this.downHandlerRef = node;
},
saveInput(node) {
this.inputRef = node;
},
},
render() {
const props = { ...this.$props, ...this.$attrs };
const {
prefixCls,
disabled,
@ -631,8 +645,10 @@ export default {
autoComplete,
upHandler,
downHandler,
} = this.$props;
class: className,
} = props;
const classes = classNames({
[className]: className,
[prefixCls]: true,
[`${prefixCls}-disabled`]: disabled,
[`${prefixCls}-focused`]: this.focused,
@ -655,6 +671,16 @@ export default {
}
}
const dataOrAriaAttributeProps = {};
for (const key in props) {
if (
props.hasOwnProperty(key) &&
(key.substr(0, 5) === 'data-' || key.substr(0, 5) === 'aria-' || key === 'role')
) {
dataOrAriaAttributeProps[key] = props[key];
}
}
const editable = !this.readOnly && !this.disabled;
// focus state, show input value
@ -665,71 +691,61 @@ export default {
let downEvents;
if (useTouch) {
upEvents = {
touchstart: editable && !upDisabledClass ? this.up : noop,
touchend: this.stop,
onTouchstart: editable && !upDisabledClass ? this.up : noop,
onTouchend: this.stop,
};
downEvents = {
touchstart: editable && !downDisabledClass ? this.down : noop,
touchend: this.stop,
onTouchstart: editable && !downDisabledClass ? this.down : noop,
onTouchend: this.stop,
};
} else {
upEvents = {
mousedown: editable && !upDisabledClass ? this.up : noop,
mouseup: this.stop,
mouseleave: this.stop,
onMousedown: editable && !upDisabledClass ? this.up : noop,
onMouseup: this.stop,
onMouseleave: this.stop,
};
downEvents = {
mousedown: editable && !downDisabledClass ? this.down : noop,
mouseup: this.stop,
mouseleave: this.stop,
onMousedown: editable && !downDisabledClass ? this.down : noop,
onMouseup: this.stop,
onMouseleave: this.stop,
};
}
const isUpDisabled = !!upDisabledClass || disabled || readOnly;
const isDownDisabled = !!downDisabledClass || disabled || readOnly;
const {
mouseenter = noop,
mouseleave = noop,
mouseover = noop,
mouseout = noop,
} = getListeners(this);
const contentProps = {
on: { mouseenter, mouseleave, mouseover, mouseout },
class: classes,
attrs: { title: this.$props.title },
};
const upHandlerProps = {
props: {
disabled: isUpDisabled,
prefixCls,
},
attrs: {
unselectable: 'unselectable',
role: 'button',
'aria-label': 'Increase Value',
'aria-disabled': !!isUpDisabled,
},
disabled: isUpDisabled,
prefixCls,
unselectable: 'unselectable',
role: 'button',
'aria-label': 'Increase Value',
'aria-disabled': !!isUpDisabled,
class: `${prefixCls}-handler ${prefixCls}-handler-up ${upDisabledClass}`,
on: upEvents,
ref: 'up',
...upEvents,
ref: this.saveUp,
};
const downHandlerProps = {
props: {
disabled: isDownDisabled,
prefixCls,
},
attrs: {
unselectable: 'unselectable',
role: 'button',
'aria-label': 'Decrease Value',
'aria-disabled': !!isDownDisabled,
},
disabled: isDownDisabled,
prefixCls,
unselectable: 'unselectable',
role: 'button',
'aria-label': 'Decrease Value',
'aria-disabled': !!isDownDisabled,
class: `${prefixCls}-handler ${prefixCls}-handler-down ${downDisabledClass}`,
on: downEvents,
ref: 'down',
...downEvents,
ref: this.saveDown,
};
// ref for test
return (
<div {...contentProps}>
<div
class={classes}
style={props.style}
title={props.title}
onMouseenter={props.onMouseenter}
onMouseleave={props.onMouseleave}
onMouseover={props.onMouseover}
onMouseout={props.onMouseout}
>
<div class={`${prefixCls}-handler-wrap`}>
<InputHandler {...upHandlerProps}>
{upHandler || (
@ -757,7 +773,7 @@ export default {
aria-valuemax={this.max}
aria-valuenow={sValue}
required={this.required}
type={this.type}
type={props.type}
placeholder={this.placeholder}
onClick={this.handleInputClick}
class={`${prefixCls}-input`}
@ -767,7 +783,7 @@ export default {
onBlur={this.onBlur}
onKeydown={editable ? this.onKeyDown : noop}
onKeyup={editable ? this.onKeyUp : noop}
maxLength={this.maxLength}
maxlength={props.maxLength}
readOnly={this.readOnly}
disabled={this.disabled}
max={this.max}
@ -777,9 +793,10 @@ export default {
title={this.title}
id={this.id}
onInput={this.onChange}
ref="inputRef"
ref={this.saveInput}
value={inputDisplayValue}
pattern={this.pattern}
{...dataOrAriaAttributeProps}
/>
</div>
</div>

77
components/vc-m-feedback/src/TouchFeedback.jsx

@ -1,4 +1,5 @@
import { initDefaultProps } from '../../_util/props-util';
import classNames from 'classnames';
import { initDefaultProps, getSlot } from '../../_util/props-util';
import { cloneElement } from '../../_util/vnode';
import warning from '../../_util/warning';
import BaseMixin from '../../_util/BaseMixin';
@ -7,10 +8,12 @@ import { ITouchProps } from './PropTypes';
export default {
name: 'TouchFeedback',
mixins: [BaseMixin],
inheritAttrs: false,
props: initDefaultProps(ITouchProps, {
disabled: false,
}),
data() {
this.child = null;
return {
active: false,
};
@ -26,8 +29,12 @@ export default {
},
methods: {
triggerEvent(type, isActive, ev) {
// input-numberTouchableantd
this.$emit(type, ev);
const eventType = `on${type}`;
const { child } = this;
if (child.props[eventType]) {
child.props[eventType](ev);
}
if (isActive !== this.active) {
this.setState({
active: isActive,
@ -35,60 +42,66 @@ export default {
}
},
onTouchStart(e) {
this.triggerEvent('touchstart', true, e);
this.triggerEvent('Touchstart', true, e);
},
onTouchMove(e) {
this.triggerEvent('touchmove', false, e);
this.triggerEvent('Touchmove', false, e);
},
onTouchEnd(e) {
this.triggerEvent('touchend', false, e);
this.triggerEvent('Touchend', false, e);
},
onTouchCancel(e) {
this.triggerEvent('touchcancel', false, e);
this.triggerEvent('Touchcancel', false, e);
},
onMouseDown(e) {
// pc simulate mobile
this.triggerEvent('mousedown', true, e);
this.triggerEvent('Mousedown', true, e);
},
onMouseUp(e) {
this.triggerEvent('mouseup', false, e);
this.triggerEvent('Mouseup', false, e);
},
onMouseLeave(e) {
this.triggerEvent('mouseleave', false, e);
this.triggerEvent('Mouseleave', false, e);
},
},
render() {
const { disabled, activeClassName = '', activeStyle = {} } = this.$props;
const child = this.$slots.default;
let child = getSlot(this);
if (child.length !== 1) {
warning(false, 'm-feedback组件只能包含一个子元素');
return null;
}
let childProps = {
on: disabled
? {}
: {
touchstart: this.onTouchStart,
touchmove: this.onTouchMove,
touchend: this.onTouchEnd,
touchcancel: this.onTouchCancel,
mousedown: this.onMouseDown,
mouseup: this.onMouseUp,
mouseleave: this.onMouseLeave,
},
};
const events = disabled
? undefined
: {
onTouchstart: this.onTouchStart,
onTouchmove: this.onTouchMove,
onTouchend: this.onTouchEnd,
onTouchcancel: this.onTouchCancel,
onMousedown: this.onMouseDown,
onMouseup: this.onMouseUp,
onMouseleave: this.onMouseLeave,
};
child = child[0];
this.child = child;
if (!disabled && this.active) {
childProps = {
...childProps,
...{
style: activeStyle,
class: activeClassName,
},
};
let { style, class: className } = child.props;
if (activeStyle !== false) {
if (activeStyle) {
style = { ...style, ...activeStyle };
}
className = classNames(className, activeClassName);
}
return cloneElement(child, {
class: className,
style,
...events,
});
}
return cloneElement(child, childProps);
return cloneElement(child, events);
},
};

2
examples/App.vue

@ -4,7 +4,7 @@
</div>
</template>
<script>
import demo from '../antdv-demo/docs/input/demo/tooltip';
import demo from '../antdv-demo/docs/input-number/demo/index';
export default {
components: {

2
examples/index.js

@ -3,6 +3,7 @@ import { createApp } from 'vue';
import App from './App.vue';
import {
Input,
InputNumber,
Rate,
Button,
Upload,
@ -41,4 +42,5 @@ app
.use(Tooltip)
.use(Col)
.use(Row)
.use(InputNumber)
.mount('#app');

Loading…
Cancel
Save