这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战
TIP 👉 不飞则已,一飞冲天;不鸣则已,一鸣惊人。——《史记·滑稽列传》
前言
Web Component是前端界一直非常热衷的一个领域,用第三方组件化的框架去实现的话,你需要依赖框架本身很多东西,很多时候我们只是简单的几个组件,不是很大,也不是很多,所以为了保证组件的`轻量,简单`,其实这个时候我们并不想采用第三方的框架。Input 模态对话框
import
import Input from '@/components/Input/Input';
Props
1. value
- 类型:string | number(必填)
- 默认值:无
- 说明:输入框的内容
2. size
- 类型:string
- 默认值:无(框高32px)
- 说明:large(框高40px)small(框高24px)
3. maxLength
- 类型:string | number
- 默认值:无
- 说明:输入框可输入的最大字符数
4. disabled
- 类型:bool
- 默认值:无
- 说明:是否禁用,true禁用,false可用
5. placeholder
- 类型:string
- 默认值:无
- 说明:输入框描述信息
6. prefix
- 类型:ReactNode
- 默认值:无
- 说明:前缀图标
- 不传,无前缀图标;传节点,自定义前缀图标
7. suffix
- 类型:ReactNode
- 默认值:无
- 说明:后缀图标
- 不传,无后缀图标;传节点,自定义后缀图标
8. allowClear
- 类型:bool
- 默认值:无
- 说明:是否显示清空图标,true显示,false不显示
9. onChange
- 类型:func(必填)
- 默认值:无
- 说明:输入内容时触发的回调函数
10. onPressEnter
- 类型:func
- 默认值:无
- 说明:回车按键触发的回调函数
11. onBlur
- 类型:func
- 默认值:无
- 说明:输入框失去光标触发的回调函数
让我们来实现一款input组件
import React from 'react';
import { Component, PropTypes } from '../utils/';
import Icon from '../icon';
export default class Input extends Component {
static defaultProps = {
prefixCls: 'input',
type: 'text',
autoComplete: 'off',
onChange() { },
onSearch() { },
onKeyUp() { },
}
constructor(props) {
super(props);
this.state = {
value: props.value,
placeholder: props.placeholder,
};
}
componentWillReceiveProps(...props) {
this.setState({
...props,
});
}
handleKeyUp(e) {
const { onSearch, onKeyUp } = this.props;
if (e.key === 'Enter') {
onSearch(e, e.target.value);
}
onKeyUp(e);
}
// Input-Number 等其它组件使用的方法
focus() {
(this.input || this.textarea).focus();
}
blur() {
(this.input || this.textarea).blur();
}
handleChange(e) {
const { onChange, length } = this.props;
let val = e.target.value;
if (val.length > length) {
val = val.slice(0, length);
e.target.value = val;
}
this.setState({ value: val });
onChange(e, val);
}
handleClick(type, e) {
if (this.props[type]) {
this.props[type](e, this.state.value);
}
}
renderIcon(type) {
const { prefixCls, leftIcon, rightIcon, onIconClick, onPreIconClick, onIconMouseOut, onPreIconMouseOut, onIconMouseOver, onPreIconMouseOver } = this.props;
let icons;
if (type === 'rightIcon' && typeof rightIcon === 'string') icons = rightIcon;
if (type === 'leftIcon' && typeof leftIcon === 'string') icons = leftIcon;
const renderIcon = () => {
if ((typeof leftIcon === 'string' && icons) || (typeof rightIcon === 'string' && icons)) {
return (
<Icon
className="input-icon-inner"
type={icons}
onClick={this.handleClick.bind(this, type === 'icon' ? 'onIconClick' : 'onPreIconClick')}
onMouseOver={this.handleClick.bind(this, type === 'icon' ? 'onIconMouseOver' : 'onPreIconMouseOver')}
onMouseOut={this.handleClick.bind(this, type === 'icon' ? 'onIconMouseOut' : 'onPreIconMouseOut')}
/>
);
}
return type === 'rightIcon' ? rightIcon : leftIcon;
};
return (
<div className={this.classNames({
[`${prefixCls}-icon-left`]: type === 'leftIcon' && leftIcon,
[`${prefixCls}-icon-right`]: type === 'rightIcon' && rightIcon,
event: (type === 'leftIcon' && onPreIconClick) ||
(type === 'rightIcon' && onIconClick) ||
(type === 'leftIcon' && onPreIconMouseOut) ||
(type === 'rightIcon' && onIconMouseOut) ||
(type === 'leftIcon' && onPreIconMouseOut) ||
(type === 'rightIcon' && onIconMouseOver) ||
(type === 'leftIcon' && onPreIconMouseOver),
})}
>
{renderIcon()}
</div>
);
}
render() {
const { prefixCls, className, style, type, size, length, leftIcon, rightIcon, value,
onSearch,
onIconClick,
onPreIconClick,
onIconMouseOut,
onPreIconMouseOut,
onIconMouseOver,
onPreIconMouseOver,
addonBefore,
addonAfter,
height,
...other
} = this.props;
const cls = this.classNames(`${prefixCls}`, className, {
textarea: type === 'textarea',
'w-disabled': this.props.disabled,
});
if (type === 'textarea') {
return (
<textarea
className={this.classNames(cls, `${prefixCls}-inner`)}
{...other}
value={value}
placeholder={!value ? this.state.placeholder : ''}
ref={(elm) => { this.textarea = elm; }}
type={type}
style={style}
onChange={this.handleChange.bind(this)}
/>
);
}
return (
<div
style={style}
className={this.classNames(cls, {
[`${prefixCls}-${size}`]: size,
[`${prefixCls}-icon`]: leftIcon || rightIcon,
[`${prefixCls}-addon`]: addonBefore || addonAfter,
})}
>
{addonBefore && <span className={`${prefixCls}-addon-before`}>{addonBefore}</span>}
{leftIcon && this.renderIcon.bind(this)('leftIcon')}
{rightIcon && this.renderIcon.bind(this)('rightIcon')}
<input
{...other}
type={type}
ref={(elm) => { this.input = elm; }}
className={this.classNames(`${prefixCls}-inner`, {
[`${prefixCls}-p-left`]: leftIcon,
[`${prefixCls}-p-right`]: rightIcon,
'addon-before': addonBefore,
'addon-after': addonAfter,
})}
value={value}
placeholder={!value ? this.state.placeholder : ''}
onChange={this.handleChange.bind(this)}
onKeyUp={this.handleKeyUp.bind(this)}
style={{height: height}}
/>
{addonAfter && <span className={`${prefixCls}-addon-after`}>{addonAfter}</span>}
</div>
);
}
}
Input.propTypes = {
prefixCls: PropTypes.string,
type: PropTypes.string,
autoComplete: PropTypes.string,
size: PropTypes.oneOf(['large', 'small', 'mini']),
length: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
rightIcon: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
leftIcon: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
onChange: PropTypes.func,
onSearch: PropTypes.func,
onKeyUp: PropTypes.func,
addonBefore: PropTypes.node,
addonAfter: PropTypes.node,
};
index.js
import Input from './Input';
import './input.scss';
export default Input;
样式这块就先不放了
「欢迎在评论区讨论」