Skip to content

Commit

Permalink
fix(input): fix input 受控
Browse files Browse the repository at this point in the history
  • Loading branch information
ming680 committed Sep 24, 2024
1 parent 3c09c5c commit 46ea4de
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 21 deletions.
2 changes: 0 additions & 2 deletions src/input/_example/align.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import 'tdesign-web-components/space';
import { Component } from 'omi';

export default class InputAlign extends Component {
inputValue = '';

render() {
return (
<t-space direction="vertical" style={{ width: '100%' }}>
Expand Down
1 change: 1 addition & 0 deletions src/input/_example/auto-width.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export default class InputAutowidth extends Component {
defaultValue="宽度自适应"
onChange={(value) => {
this.inputValue = value;
this.update();
}}
/>
</div>
Expand Down
2 changes: 2 additions & 0 deletions src/input/_example/base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default class InputBase extends Component {
placeholder="请输入内容(无默认值)"
onChange={(value) => {
this.value1 = value;
this.update();
console.log('change', value);
}}
onFocus={() => {
Expand All @@ -30,6 +31,7 @@ export default class InputBase extends Component {
onChange={(value) => {
console.log(value);
this.value2 = value;
this.update();
}}
onEnter={(value) => {
console.log(value);
Expand Down
2 changes: 2 additions & 0 deletions src/input/_example/borderless.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default class InputBase extends Component {
placeholder="请输入内容(无默认值)"
onChange={(value) => {
this.value1 = value;
this.update();
console.log(value);
}}
/>
Expand All @@ -24,6 +25,7 @@ export default class InputBase extends Component {
onChange={(value) => {
console.log(value);
this.value2 = value;
this.update();
}}
onEnter={(value) => {
console.log(value);
Expand Down
12 changes: 10 additions & 2 deletions src/input/_example/clearable.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'tdesign-icons-web-components/esm/components/lock-on';
import 'tdesign-web-components/input';
import 'tdesign-web-components/space';
import 'tdesign-icons-web-components/esm/components/lock-on';

import { Component } from 'omi';

Expand All @@ -10,7 +10,15 @@ export default class InputBase extends Component {
render() {
return (
<t-space direction="vertical">
<t-input value={this.value1} placeholder="请输入" clearable />
<t-input
value={this.value1}
placeholder="请输入"
onChange={(value) => {
this.value1 = value;
this.update();
}}
clearable
/>
</t-space>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/input/_example/format.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default class InputForMat extends Component {
value={this.inputValue}
onChange={(value) => {
this.inputValue = value;
this.update();
}}
status={inputStatus}
format={format}
Expand Down
24 changes: 21 additions & 3 deletions src/input/_example/password.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'tdesign-icons-web-components/esm/components/lock-on';
import 'tdesign-web-components/input';
import 'tdesign-web-components/space';
import 'tdesign-icons-web-components/esm/components/lock-on';

import { Component } from 'omi';

Expand All @@ -12,8 +12,26 @@ export default class InputBase extends Component {
render() {
return (
<t-space direction="vertical">
<t-input value={this.value1} placeholder="请输入密码" type="password" prefixIcon={<t-icon-lock-on />} />
<t-input value={this.value2} placeholder="请输入密码" type="password" prefixIcon={<t-icon-lock-on />} />
<t-input
value={this.value1}
placeholder="请输入密码"
type="password"
prefixIcon={<t-icon-lock-on />}
onChange={(value) => {
this.value1 = value;
this.update();
}}
/>
<t-input
value={this.value2}
placeholder="请输入密码"
type="password"
prefixIcon={<t-icon-lock-on />}
onChange={(value) => {
this.value2 = value;
this.update();
}}
/>
</t-space>
);
}
Expand Down
9 changes: 9 additions & 0 deletions src/input/_example/status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default class InputStatus extends Component {
value={this.inputValue}
onChange={(value) => {
this.inputValue = value;
this.update();
}}
/>
<t-input
Expand All @@ -26,6 +27,7 @@ export default class InputStatus extends Component {
value={this.inputValue}
onChange={(value) => {
this.inputValue = value;
this.update();
}}
/>
</t-space>
Expand All @@ -35,6 +37,7 @@ export default class InputStatus extends Component {
value={this.inputValue}
onChange={(value) => {
this.inputValue = value;
this.update();
}}
status="success"
/>
Expand All @@ -43,6 +46,7 @@ export default class InputStatus extends Component {
value={this.inputValue}
onChange={(value) => {
this.inputValue = value;
this.update();
}}
status="warning"
/>
Expand All @@ -51,6 +55,7 @@ export default class InputStatus extends Component {
value={this.inputValue}
onChange={(value) => {
this.inputValue = value;
this.update();
}}
status="error"
/>
Expand All @@ -62,6 +67,7 @@ export default class InputStatus extends Component {
value={this.inputValue}
onChange={(value) => {
this.inputValue = value;
this.update();
}}
/>
<t-input
Expand All @@ -70,6 +76,7 @@ export default class InputStatus extends Component {
value={this.inputValue}
onChange={(value) => {
this.inputValue = value;
this.update();
}}
status="success"
/>
Expand All @@ -79,6 +86,7 @@ export default class InputStatus extends Component {
value={this.inputValue}
onChange={(value) => {
this.inputValue = value;
this.update();
}}
status="warning"
/>
Expand All @@ -88,6 +96,7 @@ export default class InputStatus extends Component {
value={this.inputValue}
onChange={(value) => {
this.inputValue = value;
this.update();
}}
status="error"
/>
Expand Down
54 changes: 40 additions & 14 deletions src/input/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export default class Input extends Component<InputProps> {

composingRef = createRef();

value;
innerValue;

composingValue = '';

Expand All @@ -103,6 +103,10 @@ export default class Input extends Component<InputProps> {

eventProps;

private get isControlled() {
return Reflect.has(this.props, 'value');
}

private handlePasswordVisible = (e: MouseEvent) => {
e.stopImmediatePropagation();
if (this.props.disabled) return;
Expand All @@ -116,7 +120,7 @@ export default class Input extends Component<InputProps> {
const { maxlength, maxcharacter, allowInputOverMax, status, onValidate, onChange } = this.props;

const { getValueByLimitNumber } = useLengthLimit({
value: this.value === undefined ? undefined : String(this.value),
value: this.innerValue === undefined ? undefined : String(this.innerValue),
status,
maxlength,
maxcharacter,
Expand All @@ -134,7 +138,9 @@ export default class Input extends Component<InputProps> {
// 完成中文输入时同步一次 composingValue
this.composingValue = newStr;
// 防止输入中文后移开光标触发mouseleave时value没更新
this.value = newStr;
if (!this.isControlled) {
this.innerValue = newStr;
}
const { onValidateChange } = useLengthLimit({
value: newStr === undefined ? undefined : String(newStr),
status: this.status,
Expand Down Expand Up @@ -189,7 +195,6 @@ export default class Input extends Component<InputProps> {
private handleClear = (e: MouseEvent) => {
const { onChange, onClear } = this.props;
this.composingValue = '';
this.value = '';
this.update();
onChange?.('', { e });
onClear?.({ e });
Expand All @@ -198,20 +203,27 @@ export default class Input extends Component<InputProps> {
private handleKeyDown = (e: KeyboardEvent) => {
const { onEnter } = this.props;
const { key, currentTarget }: { key: string; currentTarget: any } = e;
this.value = '';
key === 'Enter' && onEnter?.(currentTarget.value, { e });
this.props.onMyKeydown?.(currentTarget.value, { e });
this.props.onKeydown?.(currentTarget.value, { e });
// 防止 最外层 onKeydown
e.stopPropagation();
};

private handleKeyUp = (e: KeyboardEvent) => {
const { currentTarget }: { currentTarget: any } = e;
this.props.onMyKeyup?.(currentTarget.value, { e });
this.props.onKeyup?.(currentTarget.value, { e });
// 防止 最外层 onKeyup
e.stopPropagation();
};

private handleKeyPress = (e: KeyboardEvent) => {
const { onKeypress } = this.props;
const { currentTarget }: { currentTarget: any } = e;
onKeypress?.(currentTarget.value, { e });
// 防止 最外层 onKeypress
e.stopPropagation();
};

private handleCompositionStart = (e: CompositionEvent) => {
Expand Down Expand Up @@ -245,7 +257,7 @@ export default class Input extends Component<InputProps> {
private resizeObserver: ResizeObserver | null = null;

install() {
this.value = this.props.defaultValue || this.props.value;
this.innerValue = this.props.value || this.props.defaultValue;
this.status = this.props.status;
}

Expand All @@ -270,17 +282,22 @@ export default class Input extends Component<InputProps> {
return;
}
const target = e.currentTarget as any;
this.value = target.value;
if (!this.isControlled) {
this.innerValue = target.value;
}

const { getValueByLimitNumber, onValidateChange } = useLengthLimit({
value: this.value === undefined ? undefined : String(this.value),
value: this.innerValue === undefined ? undefined : String(this.innerValue),
status: this.status,
maxlength: this.props.maxlength,
maxcharacter: this.props.maxcharacter,
allowInputOverMax: this.props.allowInputOverMax,
onValidate: this.props.onValidate,
});
const limitedValue = getValueByLimitNumber(target.value);
this.value = limitedValue;
if (!this.isControlled) {
this.innerValue = limitedValue;
}
this.composingValue = limitedValue;
this.props.onChange?.(limitedValue);
if (!this.props.allowInputOverMax) {
Expand All @@ -290,6 +307,15 @@ export default class Input extends Component<InputProps> {
});
}

receiveProps(props: InputProps | OmiProps<InputProps, any>, oldProps: InputProps | OmiProps<InputProps, any>) {
if (
(this.isControlled && props.value !== oldProps.value) ||
(Reflect.has(oldProps, 'value') && !this.isControlled)
) {
this.innerValue = props.value;
}
}

render(props: OmiProps<InputProps>) {
const {
autoWidth,
Expand Down Expand Up @@ -322,15 +348,15 @@ export default class Input extends Component<InputProps> {
} = props;

const { limitNumber, tStatus } = useLengthLimit({
value: this.value === undefined ? undefined : String(this.value),
value: this.innerValue === undefined ? undefined : String(this.innerValue),
status,
maxlength,
maxcharacter,
allowInputOverMax,
onValidate,
});

const isShowClearIcon = ((clearable && this.value && !disabled) || showClearIconOnEmpty) && this.isHover;
const isShowClearIcon = ((clearable && this.innerValue && !disabled) || showClearIconOnEmpty) && this.isHover;

const prefixIconContent = prefixIcon
? renderIcon(
Expand Down Expand Up @@ -390,8 +416,8 @@ export default class Input extends Component<InputProps> {
}

const suffixIconContent = renderIcon('t', 'suffix', parseTNode(convertToLightDomNode(suffixIconNew)));
const labelContent = isFunction(label) ? label() : label;
const suffixContent = isFunction(suffix) ? suffix() : suffix;
const labelContent = isFunction(label) ? label({}) : label;
const suffixContent = isFunction(suffix) ? suffix({}) : suffix;

const limitNumberNode =
limitNumber() && showLimitNumber ? (
Expand All @@ -404,7 +430,7 @@ export default class Input extends Component<InputProps> {
</div>
) : null;

const innerValue = this.composingRef.current ? this.composingValue : this.value ?? '';
const innerValue = this.composingRef.current ? this.composingValue : this.innerValue ?? '';
const formatDisplayValue = format && !this.isFocused ? format(innerValue) : innerValue;
const renderInput = (
<input
Expand Down

0 comments on commit 46ea4de

Please sign in to comment.