import React, { Component } from 'react';
import { Input, Button } from 'antd';
import styles from './index.less';
const ADD_DELAY = 500;
export default class SearchBox extends Component {
static defaultProps = {
value: undefined,
defaultOptions: [],
onChange: (value = '') => {},
onSearch: (value = '') => {},
onOptionsUpdate: (options = []) => {},
maxLength: 30,
placeholder: '输入关键字',
allowClear: false,
zIndex: 10,
maxOptionsLength: 10,
loading: false,
enterButton: '查询',
};
state = {
controlled: this.props.value !== undefined && typeof this.props.value === 'string',
value: '',
options: this.props.defaultOptions.slice(),
visibleOptions: false,
};
refInput = React.createRef();
onInputChange = (event = {}) => {
const value = event.target.value;
if (this.state.controlled) {
this.props.onChange && this.props.onChange(value);
} else {
this.setState({ value });
}
};
onHitEnter = (event = {}) => {
const { keyCode, which } = event;
if (keyCode === 13 || which === 13) {
this.addOptions(this.useValue);
this.props.onSearch && this.props.onSearch(this.useValue);
this.refInput.current.blur();
}
};
onSearchButtonClick = () => {
this.addOptions(this.useValue);
if (this.props.onSearch) {
this.props.onSearch(this.useValue);
}
};
addOptions = (value = '') => {
if (!value.trim()) {
return;
}
let { options = [] } = this.state;
const included = options.some(v => v === value);
if (!included) {
const t = setTimeout(() => {
clearTimeout(t);
options.unshift(value);
options = options.slice(0, Math.max(3, this.props.maxOptionsLength));
this.setState({ options }, () => {
if (this.props.onOptionsUpdate) {
this.props.onOptionsUpdate(options);
}
});
}, ADD_DELAY);
}
};
onOptionClick = (value = '') => {
if (this.state.controlled) {
this.props.onChange && this.props.onChange(value);
} else {
this.setState({ value });
}
this.props.onSearch && this.props.onSearch(value);
};
get useValue() {
return this.state.controlled ? this.props.value : this.state.value;
}
render() {
const { maxLength, placeholder, allowClear, style, zIndex, loading, enterButton } = this.props;
const { options = [], visibleOptions } = this.state;
return (
<div className={styles.container} style={{ ...style, zIndex }}>
<Input
ref={this.refInput}
className={styles.input}
type="text"
maxLength={maxLength}
placeholder={placeholder}
allowClear={allowClear}
value={this.useValue}
onChange={this.onInputChange}
onKeyUp={this.onHitEnter}
onFocus={() => this.setState({ visibleOptions: true })}
onBlur={() => this.setState({ visibleOptions: false })}
/>
<Button
loading={loading}
type="primary"
className={styles.search_btn}
onClick={this.onSearchButtonClick}
>
{enterButton}
</Button>
<div className={loading ? styles.loading_active : styles.loading}></div>
<ul
className={options.length > 0 && visibleOptions ? styles.options_visible : styles.options}
>
{options.map(opt => (
<li
key={opt}
className={styles.option_item}
onClick={() => this.onOptionClick(opt)}
title={opt}
>
{opt}
</li>
))}
</ul>
</div>
);
}
}