update input

pull/802/head
wangxueliang 2019-04-07 17:19:18 +08:00
parent ca7a4becbc
commit 22b051f0a5
15 changed files with 376 additions and 98 deletions

View File

@ -1,9 +1,10 @@
import { filterEmpty } from '../_util/props-util'; import { filterEmpty } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
export default { export default {
name: 'AInputGroup', name: 'AInputGroup',
props: { props: {
prefixCls: { prefixCls: {
default: 'ant-input-group',
type: String, type: String,
}, },
size: { size: {
@ -13,9 +14,15 @@ export default {
}, },
compact: Boolean, compact: Boolean,
}, },
inject: {
configProvider: { default: () => ({}) },
},
computed: { computed: {
classes() { classes() {
const { prefixCls, size, compact = false } = this; const { prefixCls: customizePrefixCls, size, compact = false } = this;
const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls;
const prefixCls = getPrefixCls('input-group', customizePrefixCls);
return { return {
[`${prefixCls}`]: true, [`${prefixCls}`]: true,
[`${prefixCls}-lg`]: size === 'large', [`${prefixCls}-lg`]: size === 'large',

View File

@ -4,6 +4,10 @@ import omit from 'omit.js';
import inputProps from './inputProps'; import inputProps from './inputProps';
import { hasProp, getComponentFromProp } from '../_util/props-util'; import { hasProp, getComponentFromProp } from '../_util/props-util';
import { isIE, isIE9 } from '../_util/env'; import { isIE, isIE9 } from '../_util/env';
import { ConfigConsumerProps } from '../config-provider';
import Password from './Password';
import Icon from '../icon';
import warning from '../_util/warning';
function noop() {} function noop() {}
@ -14,6 +18,10 @@ function fixControlledValue(value) {
return value; return value;
} }
function hasPrefixSuffix(props) {
return 'prefix' in props || props.suffix || props.allowClear;
}
export default { export default {
name: 'AInput', name: 'AInput',
inheritAttrs: false, inheritAttrs: false,
@ -24,6 +32,9 @@ export default {
props: { props: {
...inputProps, ...inputProps,
}, },
inject: {
configProvider: { default: () => ({}) },
},
data() { data() {
const { value, defaultValue } = this.$props; const { value, defaultValue } = this.$props;
return { return {
@ -49,22 +60,6 @@ export default {
} }
this.$emit('keydown', e); this.$emit('keydown', e);
}, },
handleChange(e) {
// https://github.com/vueComponent/ant-design-vue/issues/92
if (isIE && !isIE9 && this.stateValue === e.target.value) {
return;
}
if (!hasProp(this, 'value')) {
this.stateValue = e.target.value;
} else {
this.$forceUpdate();
}
if (!e.target.composing) {
this.$emit('change.value', e.target.value);
}
this.$emit('change', e);
this.$emit('input', e);
},
focus() { focus() {
this.$refs.input.focus(); this.$refs.input.focus();
@ -77,8 +72,8 @@ export default {
this.$refs.input.select(); this.$refs.input.select();
}, },
getInputClassName() { getInputClassName(prefixCls) {
const { prefixCls, size, disabled } = this.$props; const { size, disabled } = this.$props;
return { return {
[`${prefixCls}`]: true, [`${prefixCls}`]: true,
[`${prefixCls}-sm`]: size === 'small', [`${prefixCls}-sm`]: size === 'small',
@ -86,7 +81,64 @@ export default {
[`${prefixCls}-disabled`]: disabled, [`${prefixCls}-disabled`]: disabled,
}; };
}, },
renderLabeledInput(children) {
setValue(value, e) {
// https://github.com/vueComponent/ant-design-vue/issues/92
if (isIE && !isIE9 && this.stateValue === value) {
return;
}
if (!hasProp(this, 'value')) {
this.stateValue = value;
} else {
this.$forceUpdate();
}
if (!e.target.composing) {
this.$emit('change.value', value);
}
this.$emit('change', e);
this.$emit('input', e);
},
handleReset(e) {
this.setValue('', e);
},
handleChange(e) {
this.setValue(e.target.value, e);
},
renderClearIcon(prefixCls) {
const { allowClear } = this.$props;
const { stateValue } = this;
if (!allowClear || stateValue === undefined || stateValue === null || stateValue === '') {
return null;
}
return (
<Icon
type="close-circle"
theme="filled"
onClick={this.handleReset}
class={`${prefixCls}-clear-icon`}
role="button"
/>
);
},
renderSuffix(prefixCls) {
const { allowClear } = this.$props;
let suffix = getComponentFromProp(this, 'suffix');
if (suffix || allowClear) {
return (
<span class={`${prefixCls}-suffix`}>
{this.renderClearIcon(prefixCls)}
{suffix}
</span>
);
}
return null;
},
renderLabeledInput(prefixCls, children) {
const props = this.$props; const props = this.$props;
let addonAfter = getComponentFromProp(this, 'addonAfter'); let addonAfter = getComponentFromProp(this, 'addonAfter');
let addonBefore = getComponentFromProp(this, 'addonBefore'); let addonBefore = getComponentFromProp(this, 'addonBefore');
@ -95,24 +147,24 @@ export default {
return children; return children;
} }
const wrapperClassName = `${props.prefixCls}-group`; const wrapperClassName = `${prefixCls}-group`;
const addonClassName = `${wrapperClassName}-addon`; const addonClassName = `${wrapperClassName}-addon`;
addonBefore = addonBefore ? <span class={addonClassName}>{addonBefore}</span> : null; addonBefore = addonBefore ? <span class={addonClassName}>{addonBefore}</span> : null;
addonAfter = addonAfter ? <span class={addonClassName}>{addonAfter}</span> : null; addonAfter = addonAfter ? <span class={addonClassName}>{addonAfter}</span> : null;
const className = { const mergedWrapperClassName = {
[`${props.prefixCls}-wrapper`]: true, [`${prefixCls}-wrapper`]: true,
[wrapperClassName]: addonBefore || addonAfter, [wrapperClassName]: addonBefore || addonAfter,
}; };
const groupClassName = classNames(`${props.prefixCls}-group-wrapper`, { const mergedGroupClassName = classNames(`${prefixCls}-group-wrapper`, {
[`${props.prefixCls}-group-wrapper-sm`]: props.size === 'small', [`${prefixCls}-group-wrapper-sm`]: props.size === 'small',
[`${props.prefixCls}-group-wrapper-lg`]: props.size === 'large', [`${prefixCls}-group-wrapper-lg`]: props.size === 'large',
}); });
return ( return (
<span class={groupClassName}> <span class={mergedGroupClassName}>
<span class={className}> <span class={mergedWrapperClassName}>
{addonBefore} {addonBefore}
{children} {children}
{addonAfter} {addonAfter}
@ -120,17 +172,15 @@ export default {
</span> </span>
); );
}, },
renderLabeledIcon(children) { renderLabeledIcon(prefixCls, children) {
const { prefixCls, size } = this.$props; const { size } = this.$props;
let prefix = getComponentFromProp(this, 'prefix'); let suffix = this.renderSuffix(prefixCls);
let suffix = getComponentFromProp(this, 'suffix'); if (!hasPrefixSuffix(this.$props)) {
if (!prefix && !suffix) {
return children; return children;
} }
let prefix = getComponentFromProp(this, 'prefix');
prefix = prefix ? <span class={`${prefixCls}-prefix`}>{prefix}</span> : null; prefix = prefix ? <span class={`${prefixCls}-prefix`}>{prefix}</span> : null;
suffix = suffix ? <span class={`${prefixCls}-suffix`}>{suffix}</span> : null;
const affixWrapperCls = classNames(`${prefixCls}-affix-wrapper`, { const affixWrapperCls = classNames(`${prefixCls}-affix-wrapper`, {
[`${prefixCls}-affix-wrapper-sm`]: size === 'small', [`${prefixCls}-affix-wrapper-sm`]: size === 'small',
[`${prefixCls}-affix-wrapper-lg`]: size === 'large', [`${prefixCls}-affix-wrapper-lg`]: size === 'large',
@ -144,7 +194,7 @@ export default {
); );
}, },
renderInput() { renderInput(prefixCls) {
const otherProps = omit(this.$props, [ const otherProps = omit(this.$props, [
'prefixCls', 'prefixCls',
'addonBefore', 'addonBefore',
@ -166,13 +216,13 @@ export default {
input: handleChange, input: handleChange,
change: noop, change: noop,
}, },
class: getInputClassName(), class: getInputClassName(prefixCls),
ref: 'input', ref: 'input',
}; };
if ($listeners['change.value']) { if ($listeners['change.value']) {
inputProps.directives = [{ name: 'ant-input' }]; inputProps.directives = [{ name: 'ant-input' }];
} }
return this.renderLabeledIcon(<input {...inputProps} />); return this.renderLabeledIcon(prefixCls,<input {...inputProps} />);
}, },
}, },
render() { render() {
@ -194,6 +244,9 @@ export default {
}; };
return <TextArea {...textareaProps} ref="input" />; return <TextArea {...textareaProps} ref="input" />;
} }
return this.renderLabeledInput(this.renderInput()); const { prefixCls: customizePrefixCls } = this.$props;
const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls;
const prefixCls = getPrefixCls('input', customizePrefixCls);
return this.renderLabeledInput(prefixCls, this.renderInput(prefixCls));
}, },
}; };

View File

@ -0,0 +1,86 @@
import classNames from 'classnames';
import Input from './Input';
import Icon from '../icon';
import inputProps from './inputProps';
import Button from '../button';
import { cloneElement } from '../_util/vnode';
import { getOptionProps, getComponentFromProp, isValidElement } from '../_util/props-util';
import PropTypes from '../_util/vue-types';
import BaseMixin from '../_util/BaseMixin';
const ActionMap = {
click: 'click',
hover: 'mouseover',
};
export default {
name: 'AInputPassword',
model: {
prop: 'value',
event: 'change.value',
},
props: {
...inputProps,
prefixCls: PropTypes.string.def('ant-input-password'),
inputPrefixCls: PropTypes.string.def('ant-input'),
action: PropTypes.string.def('click'),
visibilityToggle: PropTypes.bool.def(true),
},
data() {
return {
visible: false,
};
},
mixins: [BaseMixin],
methods: {
onChange(e) {
this.setState({
visible: !this.visible,
});
},
getIcon() {
const { prefixCls, action } = this.$props;
const iconTrigger = ActionMap[action] || '';
const iconProps = {
props: {
type: this.visible ? 'eye' : 'eye-invisible',
},
on: {
[iconTrigger]: this.onChange,
onMouseDown: (e) => {
// Prevent focused state lost
// https://github.com/ant-design/ant-design/issues/15173
e.preventDefault();
},
},
class: `${prefixCls}-icon`,
key: 'passwordIcon',
};
return <Icon {...iconProps} />;
},
},
render() {
const {
prefixCls,
inputPrefixCls,
size,
suffix,
visibilityToggle,
...restProps
} = this.$props;
const suffixIcon = visibilityToggle && this.getIcon();
const inputClassName = classNames(prefixCls, {
[`${prefixCls}-${size}`]: !!size,
});
return (
<Input
{...restProps}
type={this.visible ? 'text' : 'password'}
size={size}
class={inputClassName}
prefixCls={inputPrefixCls}
suffix={suffixIcon}
/>
);
},
};

View File

@ -6,6 +6,7 @@ import Button from '../button';
import { cloneElement } from '../_util/vnode'; import { cloneElement } from '../_util/vnode';
import { getOptionProps, getComponentFromProp, isValidElement } from '../_util/props-util'; import { getOptionProps, getComponentFromProp, isValidElement } from '../_util/props-util';
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import { ConfigConsumerProps } from '../config-provider';
export default { export default {
name: 'AInputSearch', name: 'AInputSearch',
@ -25,6 +26,9 @@ export default {
}, },
enterButton: PropTypes.oneOfType([PropTypes.bool, PropTypes.string, PropTypes.object]), enterButton: PropTypes.oneOfType([PropTypes.bool, PropTypes.string, PropTypes.object]),
}, },
inject: {
configProvider: { default: () => ({}) },
},
methods: { methods: {
onSearch(e) { onSearch(e) {
this.$emit('search', this.$refs.input.stateValue, e); this.$emit('search', this.$refs.input.stateValue, e);
@ -37,62 +41,96 @@ export default {
blur() { blur() {
this.$refs.input.blur(); this.$refs.input.blur();
}, },
getButtonOrIcon() { renderSuffix(prefixCls) {
const { prefixCls, size, disabled } = this; const suffix = getComponentFromProp(this, 'suffix');
const enterButton = getComponentFromProp(this, 'enterButton'); const enterButton = getComponentFromProp(this, 'enterButton');
if (enterButton) return suffix;
const node = (
<Icon
class={`${prefixCls}-icon`}
type="search"
key="searchIcon"
onClick={this.onSearch}
/>
);
if (suffix) {
let cloneSuffix = suffix;
if (isValidElement(cloneSuffix) && !cloneSuffix.key) {
cloneSuffix = cloneElement(cloneSuffix, {
key: 'originSuffix',
});
}
return [cloneSuffix, node];
}
return node;
},
renderAddonAfter(prefixCls) {
const { size, disabled } = this;
const enterButton = getComponentFromProp(this, 'enterButton');
const addonAfter = getComponentFromProp(this, 'addonAfter');
if(!enterButton) return addonAfter;
const btnClassName = `${prefixCls}-button`;
const enterButtonAsElement = Array.isArray(enterButton) ? enterButton[0] : enterButton; const enterButtonAsElement = Array.isArray(enterButton) ? enterButton[0] : enterButton;
let node; let button;
if (!enterButton) { if (
node = <Icon class={`${prefixCls}-icon`} type="search" key="searchIcon" />;
} else if (
enterButtonAsElement.tag === 'button' || enterButtonAsElement.tag === 'button' ||
(enterButtonAsElement.componentOptions && (enterButtonAsElement.componentOptions &&
enterButtonAsElement.componentOptions.Ctor.extendOptions.__ANT_BUTTON) enterButtonAsElement.componentOptions.Ctor.extendOptions.__ANT_BUTTON)
) { ) {
node = cloneElement(enterButtonAsElement, { button = cloneElement(enterButtonAsElement, {
class: `${prefixCls}-button`, class: btnClassName,
props: { size }, props: { size },
on: {
click: this.onSearch,
},
}); });
} else { } else {
node = ( button = (
<Button <Button
class={`${prefixCls}-button`} class={btnClassName}
type="primary" type="primary"
size={size} size={size}
disabled={disabled} disabled={disabled}
key="enterButton" key="enterButton"
onClick={this.onSearch}
> >
{enterButton === true ? <Icon type="search" /> : enterButton} {enterButton === true ? <Icon type="search" /> : enterButton}
</Button> </Button>
); );
} }
return cloneElement(node, { if (addonAfter) {
on: { return [button, addonAfter];
click: this.onSearch, }
},
}); return button;
}, },
}, },
render() { render() {
const { prefixCls, inputPrefixCls, size, ...others } = getOptionProps(this); const {
const suffix = getComponentFromProp(this, 'suffix'); prefixCls: customizePrefixCls,
inputPrefixCls: customizeInputPrefixCls,
size,
...others
} = getOptionProps(this);
const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls;
const prefixCls = getPrefixCls('input-search', customizePrefixCls);
const inputPrefixCls = getPrefixCls('input', customizeInputPrefixCls);
const enterButton = getComponentFromProp(this, 'enterButton'); const enterButton = getComponentFromProp(this, 'enterButton');
const addonAfter = getComponentFromProp(this, 'addonAfter');
const addonBefore = getComponentFromProp(this, 'addonBefore'); const addonBefore = getComponentFromProp(this, 'addonBefore');
const buttonOrIcon = this.getButtonOrIcon(); let inputClassName;
let searchSuffix = suffix ? [suffix, buttonOrIcon] : buttonOrIcon; if(enterButton) {
if (Array.isArray(searchSuffix)) { inputClassName = classNames(prefixCls, {
searchSuffix = searchSuffix.map((item, index) => { [`${prefixCls}-enter-button`]: !!enterButton,
if (!isValidElement(item) || item.key) { [`${prefixCls}-${size}`]: !!size,
return item;
}
return cloneElement(item, { key: index });
}); });
} else {
inputClassName = prefixCls;
} }
const inputClassName = classNames(prefixCls, {
[`${prefixCls}-enter-button`]: !!enterButton,
[`${prefixCls}-${size}`]: !!size,
});
const on = { ...this.$listeners }; const on = { ...this.$listeners };
delete on.search; delete on.search;
const inputProps = { const inputProps = {
@ -100,16 +138,18 @@ export default {
...others, ...others,
prefixCls: inputPrefixCls, prefixCls: inputPrefixCls,
size, size,
suffix: searchSuffix, suffix: this.renderSuffix(prefixCls),
addonAfter, addonAfter: this.renderAddonAfter(prefixCls),
addonBefore, addonBefore,
}, },
attrs: this.$attrs, attrs: this.$attrs,
class: inputClassName,
ref: 'input',
on: { on: {
pressEnter: this.onSearch, pressEnter: this.onSearch,
...on, ...on,
}, },
}; };
return <Input {...inputProps} class={inputClassName} ref="input" />; return <Input {...inputProps} />;
}, },
}; };

View File

@ -1,8 +1,10 @@
import classNames from 'classnames';
import omit from 'omit.js'; import omit from 'omit.js';
import ResizeObserver from 'resize-observer-polyfill'; import ResizeObserver from 'resize-observer-polyfill';
import inputProps from './inputProps'; import inputProps from './inputProps';
import calculateNodeHeight from './calculateNodeHeight'; import calculateNodeHeight from './calculateNodeHeight';
import hasProp from '../_util/props-util'; import hasProp from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
function onNextFrame(cb) { function onNextFrame(cb) {
if (window.requestAnimationFrame) { if (window.requestAnimationFrame) {
@ -36,6 +38,9 @@ export default {
...inputProps, ...inputProps,
autosize: [Object, Boolean], autosize: [Object, Boolean],
}, },
inject: {
configProvider: { default: () => ({}) },
},
data() { data() {
const { value, defaultValue } = this.$props; const { value, defaultValue } = this.$props;
return { return {
@ -105,20 +110,11 @@ export default {
if (!autosize || !this.$refs.textArea) { if (!autosize || !this.$refs.textArea) {
return; return;
} }
const minRows = autosize ? autosize.minRows : null; const { minRows, maxRows } = autosize;
const maxRows = autosize ? autosize.maxRows : null;
const textareaStyles = calculateNodeHeight(this.$refs.textArea, false, minRows, maxRows); const textareaStyles = calculateNodeHeight(this.$refs.textArea, false, minRows, maxRows);
this.textareaStyles = textareaStyles; this.textareaStyles = textareaStyles;
}, },
getTextAreaClassName() {
const { prefixCls, disabled } = this.$props;
return {
[prefixCls]: true,
[`${prefixCls}-disabled`]: disabled,
};
},
handleTextareaChange(e) { handleTextareaChange(e) {
if (!hasProp(this, 'value')) { if (!hasProp(this, 'value')) {
this.stateValue = e.target.value; this.stateValue = e.target.value;
@ -144,12 +140,13 @@ export default {
render() { render() {
const { const {
stateValue, stateValue,
getTextAreaClassName,
handleKeyDown, handleKeyDown,
handleTextareaChange, handleTextareaChange,
textareaStyles, textareaStyles,
$attrs, $attrs,
$listeners, $listeners,
prefixCls: customizePrefixCls,
disabled,
} = this; } = this;
const otherProps = omit(this.$props, [ const otherProps = omit(this.$props, [
'prefixCls', 'prefixCls',
@ -158,6 +155,13 @@ export default {
'value', 'value',
'defaultValue', 'defaultValue',
]); ]);
const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls;
const prefixCls = getPrefixCls('input', customizePrefixCls);
const cls = classNames(prefixCls, {
[`${prefixCls}-disabled`]: disabled,
});
const textareaProps = { const textareaProps = {
attrs: { ...otherProps, ...$attrs }, attrs: { ...otherProps, ...$attrs },
on: { on: {
@ -174,7 +178,7 @@ export default {
<textarea <textarea
{...textareaProps} {...textareaProps}
value={stateValue} value={stateValue}
class={getTextAreaClassName()} class={cls}
style={textareaStyles} style={textareaStyles}
ref="textArea" ref="textArea"
/> />

View File

@ -24,6 +24,7 @@ const SIZING_STYLE = [
'font-family', 'font-family',
'font-weight', 'font-weight',
'font-size', 'font-size',
'font-variant',
'text-rendering', 'text-rendering',
'text-transform', 'text-transform',
'width', 'width',
@ -37,7 +38,7 @@ const SIZING_STYLE = [
const computedStyleCache = {}; const computedStyleCache = {};
let hiddenTextarea; let hiddenTextarea;
function calculateNodeStyling(node, useCache = false) { export function calculateNodeStyling(node, useCache = false) {
const nodeRef = const nodeRef =
node.getAttribute('id') || node.getAttribute('data-reactid') || node.getAttribute('name'); node.getAttribute('id') || node.getAttribute('data-reactid') || node.getAttribute('name');

View File

@ -0,0 +1,24 @@
<cn>
#### 带移除图标
带移除图标的输入框,点击图标删除所有内容。
</cn>
<us>
#### With clear icon
Input type of password.
</us>
```html
<template>
<a-input placeholder="input with clear icon" allowClear @change="onChange" />
</template>
<script>
export default {
methods: {
onChange(e) {
console.log(e);
}
}
}
</script>
```

View File

@ -14,12 +14,14 @@ Note: You don't need `Col` to control the width in the `compact` mode.
<template> <template>
<div> <div>
<a-input-group size="large"> <a-input-group size="large">
<a-col :span="5"> <a-row :gutter="8">
<a-input defaultValue="0571" /> <a-col :span="5">
</a-col> <a-input defaultValue="0571" />
<a-col :span="8"> </a-col>
<a-input defaultValue="26888888" /> <a-col :span="8">
</a-col> <a-input defaultValue="26888888" />
</a-col>
</a-row>
</a-input-group> </a-input-group>
<br /> <br />
<a-input-group compact> <a-input-group compact>
@ -45,7 +47,7 @@ Note: You don't need `Col` to control the width in the `compact` mode.
<br /> <br />
<a-input-group compact> <a-input-group compact>
<a-input style="width: 50%" defaultValue="input content" /> <a-input style="width: 50%" defaultValue="input content" />
<a-date-picker /> <a-date-picker style="width: 50%" />
</a-input-group> </a-input-group>
<br /> <br />
<a-input-group compact> <a-input-group compact>

View File

@ -6,6 +6,8 @@ import SearchInput from './search-input';
import Size from './size'; import Size from './size';
import Group from './group'; import Group from './group';
import TextArea from './textarea'; import TextArea from './textarea';
import AllowClear from './allowClear';
import PasswordInput from './password-input';
import Addon from './addon'; import Addon from './addon';
import Tooltip from './tooltip'; import Tooltip from './tooltip';
import CN from '../index.zh-CN.md'; import CN from '../index.zh-CN.md';
@ -22,7 +24,7 @@ const md = {
Keyboard and mouse can be used for providing or changing data. Keyboard and mouse can be used for providing or changing data.
## When To Use ## When To Use
- A user input in a form field is needed. - A user input in a form field is needed.
- A search input is required. - A search input is required.
## Examples `, ## Examples `,
}; };
export default { export default {
@ -43,6 +45,8 @@ export default {
<TextArea /> <TextArea />
<Addon /> <Addon />
<Tooltip /> <Tooltip />
<AllowClear />
<PasswordInput />
<api> <api>
<CN slot='cn' /> <CN slot='cn' />
<US/> <US/>

View File

@ -0,0 +1,15 @@
<cn>
#### 密码框
密码框,版本 1.4.0 中新增。
</cn>
<us>
#### Password box
Input type of password and added in 1.4.0.
</us>
```html
<template>
<a-input-password placeholder="input password" />
</template>
```

View File

@ -11,7 +11,7 @@ For multi-line input.
```html ```html
<template> <template>
<div> <div>
<a-button @click="() => this.autoResize = !autoResize"> <a-button style="margin-bottom: 16px" @click="() => this.autoResize = !autoResize">
Auto Resize: {String(autoResize)} Auto Resize: {String(autoResize)}
</a-button> </a-button>
<a-textarea :rows="4" :autosize="autoResize" :defaultValue="defaultValue" /> <a-textarea :rows="4" :autosize="autoResize" :defaultValue="defaultValue" />

View File

@ -15,6 +15,7 @@
| suffix | The suffix icon for the Input. | string\|slot | | | suffix | The suffix icon for the Input. | string\|slot | |
| type | The type of input, see: [MDN](https://developer.mozilla.org/docs/Web/HTML/Element/input#Form_%3Cinput%3E_types)(use `Input.TextArea` instead of `type="textarea"`) | string | `text` | | type | The type of input, see: [MDN](https://developer.mozilla.org/docs/Web/HTML/Element/input#Form_%3Cinput%3E_types)(use `Input.TextArea` instead of `type="textarea"`) | string | `text` |
| value(v-model) | The input content value | string | | | value(v-model) | The input content value | string | |
| allowClear | allow to remove input content with clear icon | boolean | |
### Input Events ### Input Events
| Events Name | Description | Arguments | | Events Name | Description | Arguments |
@ -45,7 +46,7 @@ The rest of the props of `Input.TextArea` are the same as the original [textarea
| Property | Description | Type | Default | | Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- | | -------- | ----------- | ---- | ------- |
| enterButton | to show an enter button after input | boolean\|slot | false | | enterButton | to show an enter button after input. This prop is conflict with addon. | boolean\|slot | false |
### Input.Search Events ### Input.Search Events
| Events Name | Description | Arguments | | Events Name | Description | Arguments |
@ -67,3 +68,21 @@ Supports all props of `Input`.
<a-input /> <a-input />
</a-input-group> </a-input-group>
```` ````
#### Input.Password
| Property | Description | Type | Default |
| --- | --- | --- | --- |
| visibilityToggle | Whether show toggle button | boolean | true |
## FAQ
### Why Input lose focus when change `prefix/suffix`
When Input dynamic add or remove `prefix/suffix` will make Vue recreate the dom structure and new input will be not focused.
You can set an empty `<span />` element to keep the dom structure:
```jsx
const suffix = condition ? <Icon type="smile" /> : <span />;
<Input suffix={suffix} />
```

View File

@ -3,6 +3,7 @@ import Input from './Input';
import Group from './Group'; import Group from './Group';
import Search from './Search'; import Search from './Search';
import TextArea from './TextArea'; import TextArea from './TextArea';
import Password from './Password';
import antInputDirective from '../_util/antInputDirective'; import antInputDirective from '../_util/antInputDirective';
Vue.use(antInputDirective); Vue.use(antInputDirective);
@ -10,6 +11,7 @@ Vue.use(antInputDirective);
Input.Group = Group; Input.Group = Group;
Input.Search = Search; Input.Search = Search;
Input.TextArea = TextArea; Input.TextArea = TextArea;
Input.Password = Password;
/* istanbul ignore next */ /* istanbul ignore next */
Input.install = function(Vue) { Input.install = function(Vue) {
@ -17,6 +19,7 @@ Input.install = function(Vue) {
Vue.component(Input.Group.name, Input.Group); Vue.component(Input.Group.name, Input.Group);
Vue.component(Input.Search.name, Input.Search); Vue.component(Input.Search.name, Input.Search);
Vue.component(Input.TextArea.name, Input.TextArea); Vue.component(Input.TextArea.name, Input.TextArea);
Vue.component(Input.Password.name, Input.Password);
}; };
export default Input; export default Input;

View File

@ -15,6 +15,7 @@
| suffix | 带有后缀图标的 input | string\|slot | | | suffix | 带有后缀图标的 input | string\|slot | |
| type | 声明 input 类型,同原生 input 标签的 type 属性,见:[MDN](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input#属性)(请直接使用 `Input.TextArea` 代替 `type="textarea"`)。 | string | `text` | | type | 声明 input 类型,同原生 input 标签的 type 属性,见:[MDN](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input#属性)(请直接使用 `Input.TextArea` 代替 `type="textarea"`)。 | string | `text` |
| value(v-model) | 输入框内容 | string | | | value(v-model) | 输入框内容 | string | |
| allowClear | 可以点击清除图标删除内容 | boolean | |
### Input 事件 ### Input 事件
| 事件名称 | 说明 | 回调参数 | | 事件名称 | 说明 | 回调参数 |
@ -44,7 +45,7 @@
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| enterButton | 是否有确认按钮,可设为按钮文字 | boolean\|slot | false | | enterButton | 是否有确认按钮,可设为按钮文字。该属性会与 addon 冲突。 | boolean\|slot | false |
### Input.Search 事件 ### Input.Search 事件
| 事件名称 | 说明 | 回调参数 | | 事件名称 | 说明 | 回调参数 |
@ -66,3 +67,22 @@
<a-input /> <a-input />
</a-input-group> </a-input-group>
```` ````
#### Input.Password
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| visibilityToggle | 是否显示切换按钮 | boolean | true |
## FAQ
### 为什么我动态改变 `prefix/suffix`Input 会失去焦点?
当 Input 动态添加或者删除 `prefix/suffix`Vue 会重新创建 DOM 结构而新的 input 是没有焦点的。
你可以预设一个空的 `<span />` 来保持 DOM 结构不变:
```jsx
const suffix = condition ? <Icon type="smile" /> : <span />;
<Input suffix={suffix} />
```

View File

@ -1,7 +1,6 @@
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
export default { export default {
prefixCls: { prefixCls: {
default: 'ant-input',
type: String, type: String,
}, },
defaultValue: [String, Number], defaultValue: [String, Number],
@ -34,4 +33,5 @@ export default {
suffix: PropTypes.any, suffix: PropTypes.any,
spellCheck: Boolean, spellCheck: Boolean,
autoFocus: Boolean, autoFocus: Boolean,
allowClear: Boolean,
}; };