import * as React from 'react'; /** * pastate 双向数据绑定输入框组件 */ export default class Input extends React.PureComponent<{ /** 文本值 */ value: string | number /** 输入框类型, 默认为 text */ type?: "text" // 单行文本 | "textarea" // 多行文本 | "password" // 密码文本 | "number" // 纯数字文本 /** * 在文本值更新前会被调用,可用于实现自定义字符串更新逻辑 * @param newValue 将更新的新值 * @param oldValue 原始值 * @returns {string} 返回实际要更新的值 */ beforeChange?: (newValue?: string | number, oldValue?: string | number) => string | number /** 在绑定值更新后会被调用 */ afterChange?: (newValue?: string | number) => void disabled?: boolean /** [实验特性] 指定是否开启输入法输入完成才更新 state 的模式,默认为关闭 */ useComposedValue?: boolean /** 传递给输入框的 class 名 ( 用于指定 css 样式等 ) */ className?: string /** 传递给输入框的 id 名 ( 用于指定 css 样式等 ) */ id?: string }, any> { constructor(props: any){ super(props); this.innerValue = this.props.value + ''; this.isComposing = false } private innerValue: string private isComposing: boolean handleChange = e => { this.innerValue = e.target.value; this.forceUpdate() if(this.isComposing == false){ this.updateSourceValue() } } handleCompositionStart = () => { if(this.props.useComposedValue == true){ this.isComposing = true } } handleCompositionEnd = () => { if(this.props.useComposedValue == true && this.isComposing){ this.isComposing = false this.updateSourceValue() } } updateSourceValue = () => { let store = (this.props.value as any).__store__ if(!store){ throw new Error('[pastate] You can only give state node from this.props to pastate two-ways binding HOC component') } let valueTypeName: string = (Object.prototype.toString.call(this.props.value) as string).slice(8, -1); if(this.props.beforeChange){ let oldValue = valueTypeName == 'Number' ? (+ this.props.value) : (this.props.value + ''); let result = this.props.beforeChange(this.innerValue, oldValue) if(result != this.innerValue){ this.innerValue = result + ''; this.forceUpdate() } } store.set(this.props.value, valueTypeName == 'Number' ? (+this.innerValue) : (this.innerValue + '')) store.currentActionName = '[binding]' store.sync() this.props.afterChange && this.props.afterChange(this.innerValue) } componentWillReceiveProps(nextProps: any){ this.innerValue = nextProps.value + '' } render() { let props = { onChange: this.handleChange, type: this.props.type || "text", onCompositionStart: this.handleCompositionStart, onCompositionEnd: this.handleCompositionEnd, value: this.innerValue, disabled: this.props.disabled, className: this.props.className, id: this.props.id }; return this.props.type == "textarea" ?