antd Design Model弹框可拖拽(可移动)

React在使用antd项目中需要使用Model弹框,弹框展示(弹出时),需要可以拖拽移动弹框,并且不能超过可视范围。

/* eslint-disable prefer-destructuring */
import type { MouseEvent } from 'react';
import React, { Component } from 'react';
import type { ModalProps } from 'antd/lib/modal';
// import AntdModal from 'antd/lib/modal';
import { Modal } from 'antd';
import 'antd/es/modal/style/index.css';

export default class AntDraggableModal extends Component<ModalProps> {
    private simpleClass: string;
    private header: any;
    private contain: any;
    private modalContent: any;

    private mouseDownX: number = 0;
    private mouseDownY: number = 0;
    private deltaX: number = 0;
    private deltaY: number = 0;
    private sumX: number = 0;
    private sumY: number = 0;
    private offsetLeft: number = 0;
    private offsetTop: number = 0;

    constructor(props: ModalProps) {
        super(props);
        this.simpleClass = Math.random().toString(36).substring(2);
    }

    handleMove = (event: any) => {
        const deltaX = event.pageX - this.mouseDownX;
        const deltaY = event.pageY - this.mouseDownY;
        this.deltaX = deltaX;
        this.deltaY = deltaY;
        let tranX = deltaX + this.sumX;
        let tranY = deltaY + this.sumY;
        // 左侧
        if (tranX < -this.offsetLeft) {
            tranX = -this.offsetLeft;
        }
        // 右侧
        const offsetRight =
            document.body.clientWidth -
            this.modalContent.parentElement.offsetWidth -
            this.offsetLeft;
        if (tranX > offsetRight) {
            tranX = offsetRight;
        }
        // 上侧
        if (tranY < -this.offsetTop) {
            tranY = -this.offsetTop;
        }
        // 下侧
        const offsetBottom =
            document.body.clientHeight -
            this.modalContent.parentElement.offsetHeight -
            this.offsetTop;
        if (tranY > offsetBottom) {
            tranY = offsetBottom;
        }
        this.modalContent.style.transform = `translate(${tranX}px, ${tranY}px)`;
    };

    initialEvent = (visible: boolean) => {
        const { title } = this.props;
        if (title && visible) {
            setTimeout(() => {
                window.removeEventListener('mouseup', this.removeUp, false);

                this.contain = document.getElementsByClassName(this.simpleClass)[0];
                this.header = this.contain.getElementsByClassName('ant-modal-header')[0];
                this.modalContent = this.contain.getElementsByClassName('ant-modal-content')[0];
                this.offsetLeft = this.modalContent.parentElement.offsetLeft;
                this.offsetTop = this.modalContent.parentElement.offsetTop;
                this.header.style.cursor = 'all-scroll';
                this.header.onmousedown = (e: MouseEvent<HTMLDivElement>) => {
                    this.mouseDownX = e.pageX;
                    this.mouseDownY = e.pageY;
                    document.body.onselectstart = () => false;
                    window.addEventListener('mousemove', this.handleMove, false);
                };
                window.addEventListener('mouseup', this.removeUp, false);
            }, 0);
        }
    };

    removeMove = () => {
        window.removeEventListener('mousemove', this.handleMove, false);
    };

    removeUp = () => {
        // document.body.onselectstart = () => true;
        this.sumX += this.deltaX;
        this.sumY += this.deltaY;
        this.deltaX = 0;
        this.deltaY = 0;
        if (this.sumX < -this.offsetLeft) {
            this.sumX = -this.offsetLeft;
        }
        const offsetRight =
            document.body.clientWidth -
            this.modalContent.parentElement.offsetWidth -
            this.offsetLeft;
        if (this.sumX > offsetRight) {
            this.sumX = offsetRight;
        }
        // 上侧
        if (this.sumY < -this.offsetTop) {
            this.sumY = -this.offsetTop;
        }
        // 下侧
        const offsetBottom =
            document.body.clientHeight -
            this.modalContent.parentElement.offsetHeight -
            this.offsetTop;
        if (this.sumY > offsetBottom) {
            this.sumY = offsetBottom;
        }
        this.removeMove();
    };

    componentDidMount() {
        const { visible = false } = this.props;
        this.initialEvent(visible);
    }
    componentWillReceiveProps(newProps: any) {
        const { visible } = this.props;
        if (newProps.visible && !visible) {
            this.initialEvent(newProps.visible);
        }
        if (visible && !newProps.visible) {
            this.removeMove();
            window.removeEventListener('mouseup', this.removeUp, false);
        }
    }
    componentWillUnmount() {
        this.removeMove();
        window.removeEventListener('mouseup', this.removeUp, false);
    }

    render() {
        const { children, wrapClassName, ...other } = this.props;
        const wrapModalClassName = wrapClassName
            ? `${wrapClassName} ${this.simpleClass}`
            : `${this.simpleClass}`;
        return (
            <Modal {...other} wrapClassName={wrapModalClassName}>
                {children}
            </Modal>
        );
    }
}
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Antd提供了Table组件,可以实现表格的展示和编辑功能。而要实现可编辑表格和拖拽功能,需要对Table组件进行一些扩展。 1. 可编辑表格 Antd的Table组件提供了editable属性,开启该属性后,表格单元格就可以进行编辑了。同时,还需要在columns中配置每一列是否可编辑,以及编辑时的类型和属性。 例如,下面的代码可以实现一个简单的可编辑表格: ```jsx import { Table, Input, InputNumber, Popconfirm, Form } from 'antd'; import React, { useState } from 'react'; const EditableCell = ({ editing, dataIndex, title, inputType, record, index, children, ...restProps }) => { const inputNode = inputType === 'number' ? <InputNumber /> : <Input />; return ( <td {...restProps}> {editing ? ( <Form.Item name={dataIndex} style={{ margin: 0, }} rules={[ { required: true, message: `Please Input ${title}!`, }, ]} > {inputNode} </Form.Item> ) : ( children )} </td> ); }; const EditableTable = () => { const [form] = Form.useForm(); const [data, setData] = useState([ { key: '1', name: 'Edward King 0', age: 32, address: 'London, Park Lane no. 0', }, { key: '2', name: 'Edward King 1', age: 32, address: 'London, Park Lane no. 1', }, ]); const [editingKey, setEditingKey] = useState(''); const isEditing = (record) => record.key === editingKey; const edit = (record) => { form.setFieldsValue({ name: '', age: '', address: '', ...record, }); setEditingKey(record.key); }; const cancel = () => { setEditingKey(''); }; const save = async (key) => { try { const row = await form.validateFields(); const newData = [...data]; const index = newData.findIndex((item) => key === item.key); if (index > -1) { const item = newData[index]; newData.splice(index, 1, { ...item, ...row }); setData(newData); setEditingKey(''); } else { newData.push(row); setData(newData); setEditingKey(''); } } catch (errInfo) { console.log('Validate Failed:', errInfo); } }; const columns = [ { title: 'Name', dataIndex: 'name', width: '25%', editable: true, }, { title: 'Age', dataIndex: 'age', width: '15%', editable: true, }, { title: 'Address', dataIndex: 'address', width: '40%', editable: true, }, { title: 'Operation', dataIndex: 'operation', render: (_, record) => { const editable = isEditing(record); return editable ? ( <span> <a href="javascript:;" onClick={() => save(record.key)} style={{ marginRight: 8, }} > Save </a> <Popconfirm title="Sure to cancel?" onConfirm={cancel}> <a>Cancel</a> </Popconfirm> </span> ) : ( <a disabled={editingKey !== ''} onClick={() => edit(record)}> Edit </a> ); }, }, ]; const mergedColumns = columns.map((col) => { if (!col.editable) { return col; } return { ...col, onCell: (record) => ({ record, inputType: col.dataIndex === 'age' ? 'number' : 'text', dataIndex: col.dataIndex, title: col.title, editing: isEditing(record), }), }; }); return ( <Form form={form} component={false}> <Table components={{ body: { cell: EditableCell, }, }} bordered dataSource={data} columns={mergedColumns} rowClassName="editable-row" pagination={{ onChange: cancel, }} /> </Form> ); }; export default EditableTable; ``` 2. 拖拽 Antd的Table组件默认不支持拖拽功能,但是可以通过一些插件来实现。 其中,react-beautiful-dnd是一个比较常用的拖拽插件,可以很方便地和Antd的Table组件结合使用。具体实现步骤如下: 1. 安装react-beautiful-dnd插件 ```bash npm install react-beautiful-dnd ``` 2. 将Table组件封装成DragDropContext组件 ```jsx import { Table } from 'antd'; import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'; const DragTable = ({ columns, dataSource, onDragEnd }) => { return ( <DragDropContext onDragEnd={onDragEnd}> <Droppable droppableId="droppable"> {(provided) => ( <Table {...provided.droppableProps} ref={provided.innerRef} columns={columns} dataSource={dataSource} pagination={false} rowClassName="drag-row" onRow={(record, index) => ({ index, moveRow: true, })} /> )} </Droppable> </DragDropContext> ); }; export default DragTable; ``` 3. 实现onDragEnd回调函数 ```jsx const onDragEnd = (result) => { if (!result.destination) { return; } const { source, destination } = result; // 根据拖拽后的顺序重新排序dataSource const newData = [...dataSource]; const [removed] = newData.splice(source.index, 1); newData.splice(destination.index, 0, removed); // 更新dataSource setData(newData); }; ``` 最后,在页面中引用DragTable组件即可实现拖拽功能。例如: ```jsx <DragTable columns={columns} dataSource={data} onDragEnd={onDragEnd} /> ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值