v1.0.1
1. [新增]物理分页配置 2. [新增]自定义搜索模式(远程搜索) 3. [新增]下拉选高度配置 4. [修改]调整布局为flex布局 5. [修改]展开下拉选时, 自动聚焦搜索框
This commit is contained in:
@@ -8,47 +8,189 @@ class General extends Component{
|
||||
constructor(options){
|
||||
super(options);
|
||||
this.searchCid = 0;
|
||||
this.setState({ searchVal: '', });
|
||||
this.setState({
|
||||
searchVal: '',
|
||||
remote: true,
|
||||
loading: false,
|
||||
pageIndex: 1,
|
||||
pageSize: 10,
|
||||
|
||||
inputOver: true,
|
||||
});
|
||||
}
|
||||
|
||||
optionClick(item, selected, disabled, e){
|
||||
this.props.ck(item, selected, disabled);
|
||||
//阻止父组件上的事件冒泡
|
||||
this.blockClick(e);
|
||||
}
|
||||
|
||||
blockClick(e){
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
searchInputClick(e){
|
||||
e.stopPropagation();
|
||||
pagePrevClick(e){
|
||||
let index = this.state.pageIndex;
|
||||
if(index <= 1){
|
||||
return ;
|
||||
}
|
||||
this.changePageIndex(index - 1);
|
||||
}
|
||||
pageNextClick(e, size){
|
||||
let index = this.state.pageIndex;
|
||||
if(index >= size){
|
||||
return ;
|
||||
}
|
||||
this.changePageIndex(index + 1);
|
||||
}
|
||||
|
||||
changePageIndex(index){
|
||||
this.setState({
|
||||
pageIndex: index
|
||||
})
|
||||
}
|
||||
|
||||
searchInput(e){
|
||||
clearTimeout(this.searchCid);
|
||||
this.searchCid = setTimeout(() => this.setState({ searchVal: e.target.value }), this.props.delay);
|
||||
|
||||
let v = e.target.value;
|
||||
|
||||
setTimeout(() => {
|
||||
if(this.state.inputOver){
|
||||
clearTimeout(this.searchCid);
|
||||
this.searchCid = setTimeout(() => this.setState({
|
||||
searchVal: v,
|
||||
remote: true,
|
||||
}), this.props.delay);
|
||||
}
|
||||
}, 0)
|
||||
}
|
||||
|
||||
focus(){
|
||||
this.searchInputRef.focus();
|
||||
}
|
||||
|
||||
handleComposition(e){
|
||||
let type = e.type;
|
||||
|
||||
if(type === 'compositionstart'){
|
||||
this.setState({ inputOver: false })
|
||||
}else if(type === 'compositionend'){
|
||||
this.setState({ inputOver: true })
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props){
|
||||
if(!props.show){
|
||||
//清空输入框的值
|
||||
this.setState({ searchVal: '', });
|
||||
this.setState({ searchVal: '' });
|
||||
}else{
|
||||
//聚焦输入框
|
||||
setTimeout(() => this.focus(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
render({ data, prop, template, theme, sels, empty, filterable, filterMethod, delay, searchTips }) {
|
||||
render(config) {
|
||||
|
||||
let { data, prop, template, theme, sels, empty, filterable, filterMethod, remoteSearch, remoteMethod, delay, searchTips } = config
|
||||
|
||||
const { name, value, disabled } = prop;
|
||||
|
||||
const arr = (filterable ? data.filter((item, index) => filterMethod(this.state.searchVal, item, index, prop)) : data).map(item => {
|
||||
|
||||
let arr = data;
|
||||
//是否开启了搜索
|
||||
if(filterable){
|
||||
if(remoteSearch){//是否进行远程搜索
|
||||
if(this.state.remote){
|
||||
this.setState({ loading: true, remote: false });
|
||||
remoteMethod(this.state.searchVal, result => {
|
||||
this.setState({ loading: false });
|
||||
this.props.onReset(result);
|
||||
});
|
||||
}
|
||||
}else{
|
||||
arr = data.filter((item, index) => filterMethod(this.state.searchVal, item, index, prop));
|
||||
}
|
||||
}
|
||||
|
||||
const searchClass = ['xm-search', filterable ? '':'dis'].join(' ');
|
||||
const search = (
|
||||
<div class={ searchClass }>
|
||||
<i class="xm-iconfont xm-icon-sousuo"></i>
|
||||
<input type="text" class="xm-input xm-search-input" placeholder={ searchTips } value={ this.state.searchVal }
|
||||
ref={ (input) => { this.searchInputRef = input; } }
|
||||
autoFocus
|
||||
onClick={ this.blockClick.bind(this) }
|
||||
onInput={ this.searchInput.bind(this) }
|
||||
onCompositionStart={ this.handleComposition.bind(this) }
|
||||
onCompositionUpdate={ this.handleComposition.bind(this) }
|
||||
onCompositionEnd={ this.handleComposition.bind(this) }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
let paging = '';
|
||||
|
||||
if(config.paging){
|
||||
|
||||
//计算当前分页的总页码
|
||||
const size = Math.floor((arr.length - 1) / config.pageSize) + 1;
|
||||
|
||||
//如果当前页码大于总页码, 重置一下
|
||||
if(this.state.pageIndex > size){
|
||||
this.changePageIndex(size);
|
||||
}
|
||||
|
||||
//实现简单的物理分页
|
||||
let start = (this.state.pageIndex - 1) * config.pageSize;
|
||||
let end = start + config.pageSize;
|
||||
arr = arr.slice(start, end);
|
||||
|
||||
const disabledStyle = {cursor: 'no-drop', color: '#d2d2d2'};
|
||||
|
||||
let prevStyle = {}, nextStyle = {};
|
||||
this.state.pageIndex <= 1 && (prevStyle = disabledStyle);
|
||||
this.state.pageIndex == size && (nextStyle = disabledStyle);
|
||||
|
||||
const defaultCurrClass = {
|
||||
position: 'relative',
|
||||
borderRadius: '1px',
|
||||
}
|
||||
const pagingClass = 'xm-paging';
|
||||
// {
|
||||
// ''.padEnd(size, ' ').split('').map((s, i) => (
|
||||
// <span style={
|
||||
// this.state.pageIndex == i + 1 ? {
|
||||
// ...defaultCurrClass,
|
||||
// backgroundColor: theme.color,
|
||||
// borderColor: theme.color,
|
||||
// color: '#FFF',
|
||||
// } : defaultCurrClass
|
||||
// }>{ i + 1 }</span>
|
||||
// ))
|
||||
// }
|
||||
paging = (
|
||||
<div class={ pagingClass }>
|
||||
<span style={ prevStyle } onClick={ this.pagePrevClick.bind(this) }>上一页</span>
|
||||
<span>{ this.state.pageIndex } / { size }</span>
|
||||
<span style={ nextStyle } onClick={ e => this.pageNextClick.bind(this, e, size)() }>下一页</span>
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
arr = arr.map(item => {
|
||||
|
||||
const selected = !!sels.find(sel => sel[value] == item[value])
|
||||
const iconStyle = { color: selected ? theme.color : '' }
|
||||
const iconStyle = {
|
||||
color: selected ? theme.color : '',
|
||||
borderColor: theme.color,
|
||||
}
|
||||
// const className = 'xm-option' + (item.disabled ? ' disabled' : '');
|
||||
const className = ['xm-option', (item[disabled] ? ' disabled' : ''), (selected ? ' selected' : '')].join(' ');
|
||||
|
||||
return (
|
||||
<div class={className} value={ item[value] } onClick={ this.optionClick.bind(this, item, selected, item[disabled]) }>
|
||||
<div class="xm-option-icon" style={ { borderColor: theme.color, } }>
|
||||
<i class="xm-iconfont xm-icon-duox" style={ iconStyle }></i>
|
||||
</div>
|
||||
<i class="xm-option-icon xm-iconfont xm-icon-duox" style={ iconStyle }></i>
|
||||
<div class='xm-option-content' dangerouslySetInnerHTML={{ __html: template({ data, item, arr: sels, name: item[name], value: item[value] }) }}></div>
|
||||
</div>
|
||||
)
|
||||
@@ -60,18 +202,16 @@ class General extends Component{
|
||||
)
|
||||
}
|
||||
|
||||
const searchClass = ['xm-search', filterable ? '':'dis'].join(' ');
|
||||
const search = (
|
||||
<div class={ searchClass }>
|
||||
<i class="xm-iconfont xm-icon-sousuo"></i>
|
||||
<input type="text" class="xm-input xm-search-input" placeholder={ searchTips } value={ this.state.searchVal } onInput={ this.searchInput.bind(this) } onClick={ this.searchInputClick.bind(this) } />
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{ search }
|
||||
<div>{ arr }</div>
|
||||
<div onClick={ this.blockClick }>
|
||||
<div>
|
||||
{ search }
|
||||
<div style={ {maxHeight: config.height, overflow: 'auto'} }>{ arr }</div>
|
||||
{ config.paging && paging }
|
||||
</div>
|
||||
{ this.state.loading && <div class="loading" >
|
||||
<span class="loader"></span>
|
||||
</div> }
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user