UNPKG

lm-form

Version:

* 作者:liuduan * 邮箱:liuduan.05.05@163.com * 版本:**`1.0.2`**

182 lines (161 loc) 5.41 kB
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import Autoclear from './autoclear'; import './index.scss'; // wrapper for Textarea class Textarea extends Component { static propTypes = { className: PropTypes.string, // 自定义类名 placeholder: PropTypes.string, // 提示信息 defaultValue: PropTypes.string, // 默认值,用于非控制input value: PropTypes.oneOfType([ // 值,配合onChange使用 PropTypes.string, PropTypes.number ]), err: PropTypes.bool, // 判断输入是否符合错误,错误:true,正确:false maxLength: PropTypes.number, // 最大输入字数 showCounter: PropTypes.bool, // 是否显示字数提示,默认显示 onChange: PropTypes.func, onFocus: PropTypes.func, onBlur: PropTypes.func, useClear: PropTypes.bool // 是否使用clear组件 }; static defaultProps = { placeholder: '请输入', defaultValue: '', err: false, maxLength: 50, showCounter: true, onChange() { }, onFocus() { }, onBlur() { }, useClear: true }; constructor(props) { super(props); this.state = { value: 'value' in props ? props.value : props.defaultValue, xshow: false, textCounter: 0 }; this.handleChange = this.handleChange.bind(this); this.handleFocus = this.handleFocus.bind(this); this.handleBlur = this.handleBlur.bind(this); this.handleClear = this.handleClear.bind(this); this.timer = null; } componentDidMount() { const { value } = this.state; if (`${value}`.length) this.setState({ textCounter: `${value}`.length }); } componentWillReceiveProps(nextProps) { if ('value' in nextProps) { this.setState({ value: nextProps.value }); } else if ('defaultValue' in nextProps) { this.setState({ value: nextProps.defaultValue }); } } componentWillUnmount() { clearTimeout(this.timer); } handleChange(e) { e.persist(); // 在React.js中执行去抖动 const { value } = e.target; this.setState({ value, textCounter: `${value}`.length }, () => { this.controlXshow(value); // 自动显示clear btn this.props.onChange(value); }); } handleFocus(e) { e.persist(); // 在React.js中执行去抖动 // readonly直接返回 if (this.props.readOnly || this.props.readonly) return; const { value } = this.state; // 如果有值则显示x this.controlXshow(value); // 自动显示clear btn this.props.onFocus(value); } handleBlur(e) { e.persist(); // 在React.js中执行去抖动 // 通过异步操作保证先执行clearbtn中click事件,后执行input的onblur事件,保证clearbtn的存在可以清楚value const { value, xshow } = this.state; clearTimeout(this.timer); this.timer = setTimeout(() => { // 异步执行 需要先判断目标是否被删除 if (!e.target) return; // 自动隐藏clear btn if (xshow && !this.isUnmount) { this.controlXshow(''); } }, 20); this.props.onBlur(value); } handleClear() { this.setState({ value: '', textCounter: 0 }, () => { this.props.onChange(''); }); } controlXshow(value) { this.setState({ xshow: !!`${value}` }) } renderCounter(maxLength) { return ( <div className="lm-textarea-counter"> <span>{this.state.textCounter}</span>{maxLength ? '/' + maxLength : false} </div> ); } render() { const { className, defaultValue, value, placeholder, onChange, onFocus, onBlur, err, maxLength, showCounter, children, useClear, ...others } = this.props; const { xshow } = this.state; const clsPrefix = 'lm-textarea'; const cls = classNames(clsPrefix, { [`${clsPrefix}-err`]: err }, className); return ( <div className={cls}> <textarea maxLength={maxLength} value={(this.state.value || this.state.value === 0) ? this.state.value : ''} placeholder={placeholder} onChange={this.handleChange} onFocus={this.handleFocus} onBlur={this.handleBlur} {...others} /> <div className={`${clsPrefix}-tip`}> {useClear ? <Autoclear show={xshow} err={err} onClear={this.handleClear} /> : null} {showCounter ? this.renderCounter(maxLength) : null} {children} </div> </div> ); } }; export default Textarea;