react中实现拖拽排序
效果图:如下
效果说明:
1. 点击“选择”按钮,打开弹窗
2. 左侧数据是调接口回显来的
3. 点击左侧某条数据,这条被点击的数据就会被添加到右侧
4. 右侧的数据可以上下拖动换位置
5. 右侧有数据时,点击"确定" 按钮,数据就会以字符串拼接形式回显到TextArea框里,以顿号(、)分割
6. antd3里面的拖拽组件用的 react-dnd的
<DndProvider backend={HTML5Backend}> 。但在我这项目里DndProvider就不适用(项目react版本16.8.6),换一种react-dnd的低版本的写法即DragDropContext
7. 还有一些样式的问题,没写全,需要细调
代码难免会涉及到业务需求,展示部分代码,全部复制不能实现效果,仅供参考
1. 父
import React, { PureComponent } from 'react' import { Row, Input, Button, Modal, Spin } from 'antd' import DragSortingTable from './DragSortingTable' // 拖拽组件 const TextArea = Input.TextArea; class SelectProject extends PureComponent { constructor(props){ super(props) this.state= { modalVisible: false, loading: false, disabled: false, rightList: [], leftList: [], value: '', } } // 打开弹窗 openModal = () => { this.setState({ modalVisible: true }) } // 关闭弹窗 onCloseModal = () => { this.setState({ modalVisible: false }) } // 确定 onOkModal = () => { const { rightList } = this.state; let stringData = '' rightList && rightList.forEach((item, index) => { if(index < rightList.length -1){ stringData += `${item.destOrgName}` } else { stringData += item.destOrgName } }) this.setState({ modalVisible: false, value: stringData }) } // 点击左侧数据 okDataClick = (item) => { const { rightList } = this.state; let list = JSON.parse(JSON.stringify(rightList)) if(JSON.stringify(list).indexOf(JSON.stringify(item)) > -1){ message.warning(`已选择${item.destOrgName}`) return false; } list.push(item) this.setState({ rightList: list }) } // 左侧数据展示 treeLeftList = () => { const { leftList } = this.state; const radioLeftList = [] if(leftList[0]){ leftList.forEach(item => { radioLeftList.push( <div onClick={() => this.okDataClick(item)} style={{ lineHeight: '24px', padding: '4px 0', cursor: 'pointer' }}>{item.destOrgName}</div> ) }) } return radioLeftList } // 拖拽后,更新右侧数据 updataSetState = (newData) => { this.setState({ rightList: newData }) } // 删除当前行数据 clearHang = (item) => { const { rightList } = this.state; const radioLeftList = [] rightList.map(subItem => { if(subItem.destOrgName !== item.destOrgName){ radioLeftList.push(subItem) } }) this.setState({ rightList: radioLeftList }) } // 左右两列整体展示 buttonForm = () => { const { rightList } = this.state; return ( <div> <Row> <Col span={12}> <span>选择xx</span> <div>{this.treeLeftList()}</div> </Col> <Col span={12}> <div><span>已选中xx</span><a>清空</a></div> <div> <DragSortingTable2 rightList={rightList} updata={this.updataSetState} clearHang={this.clearHang} /> // 重点:用的antd3的表格可拖拽 </div> </Col> </Row> </div> ) } render () { return ( <div> <Row> <TextArea autoSize disabled={} value={this.state.value} /> <Button onClick={() => { this.setState({ modalVisible: true, loading: true, }); this.openModal() }} disabled={this.state.disabled} >选择</Button> </Row> { this.state.modalVisible ? <Modal title='' visible={this.state.modalVisible} maskCloseable={false} width='60%' onCancel={this.onCloseModal} footer={ <div style={{ textAlign: 'center'}}> <Button onClick={this.onOkModal} type='primary'>确定</Button> <Button onClick={this.onCloseModal}>关闭</Button> </div> } > <Spin spin={this.state.loading} tip='Loading'> {this.buttonForm()} </Spin> </Modal> : null } </div> ) } } export default SelectProject
拖拽子组件
相当于拖拽的table组件全部复制过来,然后主要改动是moveRow,和render里面的。
1. 至于table有表格样式,就把表格样式设置border: 0
2. 页码不显示pagination={false}
3. 当table没数据时,会显示一个空数据的图标,把空数据图标隐藏起来:z-index: -2
2. 子
import { Table } from 'antd'; import { DragDropContext, DragSource, DropTarget } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; let dragingIndex = -1; class DragSortingTable extends PureComponent { render() { const { isOver, connectDragSource, connectDropTarget, moveRow, ...restProps } = this.props; const style = { ...restProps.style, cursor: 'move' }; let { className } = restProps; if (isOver) { if (restProps.index > dragingIndex) { className += ' drop-over-downward'; } if (restProps.index < dragingIndex) { className += ' drop-over-upward'; } } return connectDragSource( connectDropTarget(<tr {...restProps} className={className} style={style} />), ); } } const rowSource = { beginDrag(props) { dragingIndex = props.index; return { index: props.index, }; }, }; const rowTarget = { drop(props, monitor) { const dragIndex = monitor.getItem().index; const hoverIndex = props.index; // Don't replace items with themselves if (dragIndex === hoverIndex) { return; } // Time to actually perform the action props.moveRow(dragIndex, hoverIndex); // Note: we're mutating the monitor item here! // Generally it's better to avoid mutations, // but it's good here for the sake of performance // to avoid expensive index searches. monitor.getItem().index = hoverIndex; }, }; const DragableBodyRow = DropTarget('row', rowTarget, (connect, monitor) => ({ connectDropTarget: connect.dropTarget(), isOver: monitor.isOver(), }))( DragSource('row', rowSource, connect => ({ connectDragSource: connect.dragSource(), }))(BodyRow), ); class DragSortingTable extends React.Component { components = { body: { row: DragableBodyRow, }, }; // 拖拽 moveRow = (dragIndex, hoverIndex) => { const {rightList, updataSetState} = this.props; const dragRow = rightList[dragIndex]; const newDataList = [...rightList] newDataList.splice(dragIndex, 1) newDataList.splice(hoverIndex, 0, dragRow) updataSetState(newDataList) }; render() { const columns = [ { title: <span style={{fontSize:'12px', color: '#71bbff'}}>{'长按可拖动排序'}</span>, dataIndex: 'destOrgName', key: 'destOrgName', render: (text, record) => { return ( <span>{text}</span> <a onClick={() => this.props.clearHang(record)} style={{ float:'right'}}>x</a> ) } } ]; return ( <Table columns={columns} dataSource={this.props.rightList} // 父级传过来的 components={this.components} onRow={(record, index) => ({ index, moveRow: this.moveRow, })} pagination={false} // 不显示页码 className='dataListTable' /> ); } } } const DragSortingTable2 = DragDropContext(HTML5Backend)(DragSortingTable) export default DragSortingTable2
原文地址:https://blog.csdn.net/qq_47305413/article/details/144700173
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!