跳到主要内容

筛选组件

less文件 antd组件



.m-arrow-close {
.ant-popover-arrow {
display: none;
}
}

.m-checbox-group-title {
font-size: 12px;
border-right: 1px solid #D9D9D9;
padding: 0px 5px;
cursor: pointer;
}

.m-checbox-group-title:hover {
color: rgb(91, 183, 225);
transition: all 1s;
}

.m-checkbox-dropdown-content {
.ant-popover-inner-content {
padding: 12px;
max-height: 300px;
overflow: hidden;
}
}

.filter-checbox-group-content {
max-height: 205px;
min-height: 100px;
overflow: auto;
}

.m-checbox-group-content-footer {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
border-top: 1px solid #f0f0f0;
padding-top: 5px;
}

主代码

import React from 'react';
import { Popover, Button, Checkbox, Space, Input, Divider } from 'antd';
import { SearchOutlined } from "@ant-design/icons";
import 'g-userGroup/src/component/IUserBehaviorSequence/EventFilter/index.less';
import _ from 'lodash';

interface IFilterProps {
title?: string,
onChange?: (value: any[]) => void,
value?: any[],
options: {
label: string,
value: string
}[],
position?: 'top' | 'left' | 'right' | 'bottom' | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight' | 'leftTop' | 'leftBottom' | 'rightTop',
/** 可以全选*/
canSelectAll?: boolean,
loading?: boolean,
triggerNode?: React.ReactNode,
size?: 'small' | 'middle' | 'large'
style?: any, // 下拉样式
}

export default class EventFilter extends React.Component<IFilterProps, {}> {

state = {
visible: false,
value: [],
searchKeywords: '',
}

// 上次选中的值
lastValue: any[] = []

componentDidMount() {
const { value } = this.props;
if (value) {
this.setState({ value })
this.lastValue = value
}
}

componentDidUpdate(preProps) {
const lastValue = preProps?.value
const curValue = this.props?.value
if (lastValue && curValue && !(_.isEqual(lastValue, curValue))) {
this.setState({ value: curValue })
this.lastValue = curValue
}
}

handleVisibleChange = (visible: boolean) => {
this.setState({ visible, searchKeywords: '', value: this.props.value })
}

handleChange = (checkedList: any[]) => {
let { options } = this.props;
let value = this.lastValue;
const { searchKeywords } = this.state;
let realOptions = options.filter(it => it.label.includes(searchKeywords));
// 对应列表value集
let realOptionsValues = realOptions.map((it) => it.value);
realOptionsValues.forEach((item) => {
// 列表的在旧的选中列表存在,在新的选中列表不存在则旧选中列表过滤掉这个值
if (
value.includes(item) &&
!checkedList.includes(item)
) {
value = value.filter(
(it) => it !== item
);
}
});
// 新列表增加的值
let changeValues = checkedList.filter((it) => {
return !value.includes(it);
});
// 合并之后最终值
let newCheckedList = [...value, ...changeValues];
this.lastValue = newCheckedList
this.setState({ value: newCheckedList })
}

onCheckAllChange = (e, hasSearch?: boolean) => {
const { options } = this.props
const { searchKeywords } = this.state
if (e.target.checked) {
if (hasSearch) {
this.handleChange(options.filter(it => it.label?.includes(searchKeywords)).map(({ value }) => value) || []);
} else {
this.handleChange(options.map(({ value }) => value));
}
} else {
this.handleChange([]);
}
};

handleOk = () => {
const { onChange } = this.props
onChange && onChange(this.state.value)
this.setState({ visible: false })
}

handleFilterReset = () => {
const { value } = this.state
if (value.length) {
this.setState({ value: [] })
this.lastValue = []
}
}

getContent = () => {
const { options, canSelectAll } = this.props;
const { value } = this.state;
const { searchKeywords } = this.state;
let renderOptions = options.filter(it => it.label?.includes(searchKeywords)) || [];
return <div className='d-flex flex-column' onClick={(e) => e.stopPropagation()}>
<Input
onChange={(e)=>{
this.setState({ searchKeywords: e.target.value })
}}
value={searchKeywords}
style={{ width: '100%', marginBottom: 15 }}
prefix={<SearchOutlined />}
placeholder="请输入"
/>
<div className='filter-checbox-group-content'>
{canSelectAll && (
<>
<Checkbox
indeterminate={value.length && value.length < options.length}
onChange={(value) => this.onCheckAllChange(value, Boolean(searchKeywords))}
checked={value.length && value.length === options.length}
>
全选
</Checkbox>
<Divider className='my-2' />
</>
)}
<Checkbox.Group onChange={this.handleChange} value={value}>
<Space direction="vertical">
{
renderOptions.map((item) => {
return (
<Checkbox
key={item.value}
value={item.value}
>
<div style={{ whiteSpace: 'nowrap' }} title={item.label}>{item.label}</div>
</Checkbox>
);
})
}
</Space>
</Checkbox.Group>
</div>
<div className='m-checbox-group-content-footer'>
<div
style={{
color: value.length ? '#5BB7E1' : "#C9C9C9",
cursor: value.length ? 'pointer' : 'not-allowed',
userSelect: 'none'
}}
onClick={this.handleFilterReset}
>
重置
</div>
<Button type='primary' size='small' onClick={this.handleOk}>确定</Button>
</div>
</div>
}

render() {
const { position, title, loading, triggerNode, style, size } = this.props;
const { visible } = this.state;
const content = this.getContent()
return <div>
<Popover
overlayClassName='m-checkbox-dropdown-content m-arrow-close'
content={content}
trigger="click"
visible={visible}
placement={position || 'bottomRight'}
onVisibleChange={this.handleVisibleChange}
// getPopupContainer={triggerNode => triggerNode.parentElement}
overlayStyle={{ ...style, zIndex: 1 }}
>
{
!triggerNode ? <Button size={size ? size : 'small'} loading={loading}>{title}</Button> :
<div style={{ userSelect: 'none' }} onClick={(e) => e.stopPropagation()}>{triggerNode}</div>
}
</Popover>
</div>
}
}

使用


<EventFilter
options={eventList}
value={selectEventList}
onChange={(value) => this.eventListChange(value)}
canSelectAll
triggerNode={
<div
style={{
display: 'flex',
alignItems: 'center',
width: 150,
marginRight: 10
}}
>
<Button type='default'>事件 {`${selectEventList.length}/${eventList.length}`}</Button>
</div>
}
/>