基于antd框架的react公共选择对话框组件

 

在项目开发过程中,对于复杂的业务选择功能很常见,而常用的下拉框选择组件往往不能满足需求,所以这里弄个针对复杂业务的可带过滤条件以及分页的选择组件,且根据不同需求进行扩展或优化。

具体实现:

1、首先新建一个SelectModal的文件夹,内部一个index.js 文件用于组件入口。

/**
 * @desc 公共选择对话框组件
 */
import React, { Component } from 'react'
import { Input, Button } from 'antd'
import SearchModal from './components'

const { Search } = Input;
const InputGroup = Input.Group;

class SelectModal extends Component {
	state = {
		dataModal: {
			isVisible: false,
		},
		// selectData: {
		// 	selectId_value: '',
		// 	selectText_value: '',
		// }
		selectData: {}
	}
	
	handleSearch(value, e) {
		this._isOpen(true);
	}
	
	handleSearchChange = (e) => {
		let value = e.target.value;
		this.setState({
			selectText_value: value
		}, () => {
			this.props.onChange(value); // 调用父组件传的回调
		})
	}
	
	handleSelect = (data, index) => {
		const selectId = this.props.config.id;
		const selectText = this.props.config.text;
		this.setState({
			selectData: {
				[selectId]: data[selectId],
				[selectText]: data[selectText]
			}
		}, () => {
			// 必须针对父组件触发或隐性触发 onchange 事件形成双向绑定,且实际传递的是当前选项值
			this.props.onChange(this.state.selectData); // 调用父组件传的回调
		})
		this._isOpen(false);
	}
	
	/**
	 * 获取当前值 id
	 */
	getDataId = () => {
		const selectId = this.props.config.id;
		return this.state.selectData[selectId];
	}
	
	/**
	 * 获取当前值 文本
	 */
	getDataName = () => {
		const selectText = this.props.config.text;
		return this.state.selectData[selectText];
	}
	
	handleOk = (value) => {
		const selectId = this.props.config.id;
		const selectText = this.props.config.text;
		this.setState({
			selectData: {
				[selectId]: value[selectId],
				[selectText]: value[selectText]
			}
		}, () => {
			// 必须针对父组件触发或隐性触发 onchange 事件形成双向绑定,且实际传递的是当前选项值
			this.props.onChange(this.state.selectData); // 调用父组件传的回调
		})
		this._isOpen(false);
	}
	
	afterClose = () => {
		this.modalRef.filterRef.current.state.value = ''
	}
	
	handleCancel = () => {
		this._isOpen(false);
	}
	
	_isOpen = (flag) => {
		this.setState({
			dataModal: {
				isVisible: flag
			}
		})
	}
	
	render() {
		const { config, value } = this.props;
		const { dataModal } = this.state;
		return (
			<>
				<InputGroup compact>
					<Input
						readOnly
						ref={(input)=> this.myinput = input}
						value={value[config.text]}
						placeholder={config.placeholder}
						allowClear
						style={{width: '80%'}}/>
					<Button type="primary"
					        icon="search"
					        style={{width: '20%'}}
					        onClick={(e) => {this.handleSearch(e)}}/>
				</InputGroup>
				<SearchModal
					modalConfig={config}
					ref={modalRef => {this.modalRef = modalRef}}
					dataModal={dataModal}
					onSelect={this.handleSelect}
					onCancel={this.handleCancel}
					onOk={this.handleOk}
					afterClose={this.afterClose}>
				</SearchModal>
			</>
		)
	}
}

export default SelectModal

2、同时在SelectModal文件夹内部新建一个component文件夹,并在该文件家中新建index.js文件,用于存放弹框的逻辑。

/**
 * @desc 公共选择对话框组件-对话框
 */
import React, { Component, useRef } from 'react'
import { Form, Input, Select, Modal, Table, Button, message, ConfigProvider, Pagination } from 'antd'
import zhCN from 'antd/es/locale/zh_CN'
import './index.scss'

const InputGroup = Input.Group;
const { Option } = Select;
const { Column } = Table;

class SearchModal extends Component {
	constructor(props) {
		super(props);
		this.state = {
			locale: zhCN,
			loading: false,
			query: {
				page: 1,
				limit: 5
			},
			filterLabel: props.modalConfig.searchOptions[0].value,
			filterValue: '',
			dataSource: [],
			selectData: '',
			total: 0,
			currentRowId: '',
			selectedRowKeys: [] // 指定选中项的 key 数组,需要和 onChange 进行配合
		}
		this.filterRef = React.createRef();
	}
	componentDidMount() {
		this.getDataList();
	}
	
	getDataList = () => {
		const { getData } = this.props.modalConfig;
		this.setState({loading: true});
		getData(this.state.query).then((response) => {
			this.setState({loading: false});
			const dataSource = response.data.data;
			const total = response.data.total;
			this.setState({dataSource, total});
		}).catch(error => {
			this.setState({loading: false});
			message.error('请求参数错误!')
		})
	}
	
	handleSearch = () => {
		this.setState((state) => ({
			query: {
				...state.query,
				[state.filterLabel]: state.filterValue
			},
		}), () => {
			this.getDataList();
		})
	}
	
	handleSelectChange = (value) => {
		this.filterRef.current.state.value = '';
		this.setState((state) => ({
			query: {
				page: 1,
				limit: 5,
				[value]: ''
			},
			filterLabel: value,
			filterValue: '',
		}))
	}
	
	handleInputChange = (e) => {
		let value = e.target.value;
		this.setState((state) => ({
			filterValue: value
		}))
	}
	
	onRowClick = (record, index) => {
		this.setState({
			selectData: record,
			currentRowId: record.id,
			selectedRowKeys: [record.id]
		})
	}
	
	onRowDoubleClick = (record, index) => {
		this.props.onSelect(record, index); // 调用父组件传的回调
	}
	
	setRowClassName = (record) => {
		return record.id === this.state.currentRowId ? 'currentRowColor' : '';
	}
	
	changePage = (page, limit) => {
		this.setState(
			(state) => ({
				query: {
					...state.query,
					page
				}
			}), () => {
				this.getDataList()
			}
		)
	}
	
	changePageSize = (current, size) => {
		this.setState(
			(state) => ({
				query: {
					...state.query,
					page: 1,
					limit: size
				}
			}), () => {
				this.getDataList()
			}
		)
	}
	
	handleModalOk = () => {
		const selectId = this.props.modalConfig.id;
		const selectText = this.props.modalConfig.text;
		let selectData = {
			[selectId]: this.state.selectData[selectId],
			[selectText]: this.state.selectData[selectText]
		}
		this.props.onOk(selectData);
	}
	
	render() {
		const { modalConfig, dataModal, onCancel, afterClose } = this.props;
		const { locale, loading, dataSource, selectedRowKeys, query, total } = this.state;
		
		const rowSelection = { // rowSelection 配置项
			type: 'radio',
			selectedRowKeys, // 需配合 onChange 使用
			onChange: (selectedRowKeys, selectedRows) => {
				this.setState({
					currentRowId: selectedRows[0].id,
					selectedRowKeys
				})
			}
		}
		
		return (
			<Modal
				title={modalConfig.title}
				width={modalConfig.width}
				visible={dataModal.isVisible}
				maskClosable={false}
				onOk={this.handleModalOk}
				onCancel={onCancel}
				afterClose={afterClose}>
				<div style={{marginBottom: '20px'}}>
					<Form>
						<InputGroup className='selectModalInputGroup' compact style={{width: '100%'}}>
							<Select defaultValue={modalConfig.searchOptions[0].value} placeholder="过滤条件" style={{width: '150px'}} onChange={this.handleSelectChange}>
								{
									modalConfig.searchOptions.map((option, index) => {
										return (
											<Option key={index} value={option.value}>{option.name}</Option>
										)
									})
								}
							</Select>
							<Input ref={this.filterRef} allowClear onChange={this.handleInputChange}/>
							<Button icon="search" onClick={this.handleSearch}></Button>
						</InputGroup>
					</Form>
				</div>
				<Table
					rowKey="_id"
					size="small"
					bordered
					loading={ loading }
					dataSource={dataSource}
					onRow={(record, index) => { // record 指的当前行的数据内容,rowkey指的是当前行的下标
						return {
							onClick: this.onRowClick.bind(this, record, index), // 点击行
							onDoubleClick: this.onRowDoubleClick.bind(this, record, index), // 双击
							onContextMenu: event => {}, // 右键菜单
							onMouseEnter: event => {}, // 鼠标移入行
							onMouseLeave: event => {} // 鼠标移出行
						}
					}}
					rowClassName={this.setRowClassName}
					pagination={false}
					rowSelection={rowSelection}
					scroll={{ y: 400 }}>
					{
						modalConfig.columns && modalConfig.columns.map((column, index) => {
							return (
								<Column
									fixed={column.fixed}
									title={column.title}
									dataIndex={column.dataIndex}
									key={column.key}
									width={column.width} />
							)
						})
					}
				</Table>
				<br/>
				<ConfigProvider locale={ locale }>
					{
						total > 0 ? (
							<>
								<Pagination
									style={{ textAlign: 'right' }}
									size="small"
									total={ total }
									current={query.page}
									defaultPageSize={query.limit}
									pageSizeOptions={["5", "10", "15"]}
									showSizeChanger
									showTotal={total => `总共 ${total} 条`}
									onChange={this.changePage}
									onShowSizeChange={this.changePageSize}
								/>
								<br/>
							</>
						) : null
					}
				</ConfigProvider>
			</Modal>
		)
	}
}

export default SearchModal

在该文件夹下补上一个css文件index.scss:

.ant-input-group.selectModalInputGroup {
  display: flex;
}

.ant-input-group.selectModalInputGroup button {
  width: 50px;
}

.currentRowColor {
  background-color: #e6f7ff;
}

.ant-table-tbody > tr.ant-table-row-selected.currentRowColor > td,
.ant-table-tbody > tr.ant-table-row-selected.currentRowColor:hover > td {
  background-color: #e6f7ff;
}

3、使用

在初始state中,需要传入的一个config配置信息:

state = {
		selectOrganConfig: {
			title: '选择机构',
			width: 800,
			placeholder: '请选择机构',
			searchOptions: [
				{ name: '机构名称', value: 'name' }
			],
			columns: [
				{
					title: '机构ID',
					width: 300,
					dataIndex: '_id',
					key: '_id'
				},
				{
					title: '机构名称',
					dataIndex: 'name',
					key: 'name'
				}
			],
			id: 'id', // 值 id 字段
			text: 'name', // 值 text 字段
			getData: getOrgans
		}
	}

如果结合antd框架的Form表单使用,有

<Form.Item label="所属机构" >
    {getFieldDecorator('organ', {
    rules: [{ required: true, message: '请选择机构!' }],
    initialValue: organData
    // 注:initialValue 此时 对应到 组件 默认的 value 上
})(
    <SelectModal
    ref={ref => {this.organRef = ref}}
    onChange={this.handleOrganChange}
    config={selectOrganConfig}/>
)}
</Form.Item>

对于组件本身而言,可以优化扩展的地方很多,如何在使用组件时更为简便,便于开发使用,需要考虑的因素还有很多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值