diff --git a/src/input/_example/align.tsx b/src/input/_example/align.tsx index 7938608..d0071a4 100644 --- a/src/input/_example/align.tsx +++ b/src/input/_example/align.tsx @@ -4,8 +4,6 @@ import 'tdesign-web-components/space'; import { Component } from 'omi'; export default class InputAlign extends Component { - inputValue = ''; - render() { return ( diff --git a/src/input/_example/auto-width.tsx b/src/input/_example/auto-width.tsx index 1e48bfe..9f253d6 100644 --- a/src/input/_example/auto-width.tsx +++ b/src/input/_example/auto-width.tsx @@ -13,6 +13,7 @@ export default class InputAutowidth extends Component { defaultValue="宽度自适应" onChange={(value) => { this.inputValue = value; + this.update(); }} /> diff --git a/src/input/_example/base.tsx b/src/input/_example/base.tsx index 594d69b..e538ac3 100644 --- a/src/input/_example/base.tsx +++ b/src/input/_example/base.tsx @@ -16,6 +16,7 @@ export default class InputBase extends Component { placeholder="请输入内容(无默认值)" onChange={(value) => { this.value1 = value; + this.update(); console.log('change', value); }} onFocus={() => { @@ -31,6 +32,7 @@ export default class InputBase extends Component { onChange={(value) => { console.log(value); this.value2 = value; + this.update(); }} onEnter={(value) => { console.log(value); diff --git a/src/input/_example/borderless.tsx b/src/input/_example/borderless.tsx index 12239a0..3c9ebc7 100644 --- a/src/input/_example/borderless.tsx +++ b/src/input/_example/borderless.tsx @@ -15,6 +15,7 @@ export default class InputBase extends Component { placeholder="请输入内容(无默认值)" onChange={(value) => { this.value1 = value; + this.update(); console.log(value); }} /> @@ -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); diff --git a/src/input/_example/clearable.tsx b/src/input/_example/clearable.tsx index 5f00f25..da6ccbc 100644 --- a/src/input/_example/clearable.tsx +++ b/src/input/_example/clearable.tsx @@ -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'; @@ -10,7 +10,15 @@ export default class InputBase extends Component { render() { return ( - + { + this.value1 = value; + this.update(); + }} + clearable + /> ); } diff --git a/src/input/_example/format.tsx b/src/input/_example/format.tsx index 72788b2..620ffbb 100644 --- a/src/input/_example/format.tsx +++ b/src/input/_example/format.tsx @@ -21,6 +21,7 @@ export default class InputForMat extends Component { value={this.inputValue} onChange={(value) => { this.inputValue = value; + this.update(); }} status={inputStatus} format={format} diff --git a/src/input/_example/password.tsx b/src/input/_example/password.tsx index 50b2d14..4fa7285 100644 --- a/src/input/_example/password.tsx +++ b/src/input/_example/password.tsx @@ -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'; @@ -12,8 +12,26 @@ export default class InputBase extends Component { render() { return ( - } /> - } /> + } + onChange={(value) => { + this.value1 = value; + this.update(); + }} + /> + } + onChange={(value) => { + this.value2 = value; + this.update(); + }} + /> ); } diff --git a/src/input/_example/status.tsx b/src/input/_example/status.tsx index c662cff..af5ea7b 100644 --- a/src/input/_example/status.tsx +++ b/src/input/_example/status.tsx @@ -18,6 +18,7 @@ export default class InputStatus extends Component { value={this.inputValue} onChange={(value) => { this.inputValue = value; + this.update(); }} /> { this.inputValue = value; + this.update(); }} /> @@ -35,6 +37,7 @@ export default class InputStatus extends Component { value={this.inputValue} onChange={(value) => { this.inputValue = value; + this.update(); }} status="success" /> @@ -43,6 +46,7 @@ export default class InputStatus extends Component { value={this.inputValue} onChange={(value) => { this.inputValue = value; + this.update(); }} status="warning" /> @@ -51,6 +55,7 @@ export default class InputStatus extends Component { value={this.inputValue} onChange={(value) => { this.inputValue = value; + this.update(); }} status="error" /> @@ -62,6 +67,7 @@ export default class InputStatus extends Component { value={this.inputValue} onChange={(value) => { this.inputValue = value; + this.update(); }} /> { this.inputValue = value; + this.update(); }} status="success" /> @@ -79,6 +86,7 @@ export default class InputStatus extends Component { value={this.inputValue} onChange={(value) => { this.inputValue = value; + this.update(); }} status="warning" /> @@ -88,6 +96,7 @@ export default class InputStatus extends Component { value={this.inputValue} onChange={(value) => { this.inputValue = value; + this.update(); }} status="error" /> diff --git a/src/input/input.tsx b/src/input/input.tsx index 4eabe0e..334f27e 100644 --- a/src/input/input.tsx +++ b/src/input/input.tsx @@ -94,7 +94,7 @@ export default class Input extends Component { composingRef = createRef(); - value; + innerValue; composingValue = ''; @@ -110,6 +110,10 @@ export default class Input extends Component { eventProps; + private get isControlled() { + return Reflect.has(this.props, 'value'); + } + private handlePasswordVisible = (e: MouseEvent) => { e.stopImmediatePropagation(); if (this.props.disabled) return; @@ -123,7 +127,7 @@ export default class Input extends Component { 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, @@ -140,7 +144,9 @@ export default class Input extends Component { // 完成中文输入时同步一次 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, @@ -195,7 +201,6 @@ export default class Input extends Component { private handleClear = (e: MouseEvent) => { const { onChange, onClear } = this.props; this.composingValue = ''; - this.value = ''; this.update(); onChange?.('', { e }); onClear?.({ e }); @@ -204,20 +209,27 @@ export default class Input extends Component { 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) => { @@ -251,7 +263,7 @@ export default class Input extends Component { 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; } @@ -278,9 +290,12 @@ export default class Input extends Component { 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, @@ -288,7 +303,9 @@ export default class Input extends Component { 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) { @@ -298,6 +315,15 @@ export default class Input extends Component { }); } + receiveProps(props: InputProps | OmiProps, oldProps: InputProps | OmiProps) { + if ( + (this.isControlled && props.value !== oldProps.value) || + (Reflect.has(oldProps, 'value') && !this.isControlled) + ) { + this.innerValue = props.value; + } + } + render(props: OmiProps) { const { innerClass, @@ -335,7 +361,7 @@ export default class Input extends Component { delete restProps.style; const { limitNumber, tStatus } = useLengthLimit({ - value: this.value === undefined ? undefined : String(this.value), + value: this.innerValue === undefined ? undefined : String(this.innerValue), status, maxlength, maxcharacter, @@ -343,7 +369,7 @@ export default class Input extends Component { onValidate, }); - const isShowClearIcon = ((clearable && this.value && !disabled) || showClearIconOnEmpty) && this.isHover; + const isShowClearIcon = ((clearable && this.innerValue && !disabled) || showClearIconOnEmpty) && this.isHover; const prefixIconContent = prefixIcon ? renderIcon( @@ -403,8 +429,8 @@ export default class Input extends Component { } const suffixIconContent = renderIcon('t', 'suffix', parseTNode(convertToLightDomNode(suffixIconNew))); - const labelContent = isFunction(label) ? (label as any)() : label; - const suffixContent = isFunction(suffix) ? (suffix as any)() : suffix; + const labelContent = isFunction(label) ? label({}) : label; + const suffixContent = isFunction(suffix) ? suffix({}) : suffix; const limitNumberNode = limitNumber() && showLimitNumber ? ( @@ -417,7 +443,7 @@ export default class Input extends Component { ) : 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 = (