暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Ant-design Modal实现可以拖动的效果

432

最近项目组在开发的时候提出了一个需求,需要让 ant-design
 Modal
实现能够拖动的功能,研究了一番,基于 and-design
 Modal
自己封装了一个antd-draggable-modal组件。

特性:

  • 支持弹出窗居中打开

  • 支持拖拽 title bar 实现拖拽

  • 支持多层弹窗拖拽

实现原理

要实现 Modal
 的拖拽,首先要弄清楚 Modal
 的位置跟什么有关系,打开浏览器,通过 F12
 调试窗口可以看到, Modal
 的位置跟 class
 属性为 ant-modal-content
 的元素有关。

因此接下来的思路就很简单了,通过监听鼠标事件来设置 ant-modal-content
 元素的 transform
 属性来实现 Modal
 位置的调整。

代码如下:

  1. import React, { Component, MouseEvent } from 'react';

  2. import AntdModal, { ModalProps } from 'antd/lib/modal';

  3. import 'antd/es/modal/style/index.css';


  4. export default class AntDraggableModal extends Component<ModalProps> {

  5. private simpleClass: string;

  6. private header: any;

  7. private contain: any;

  8. private modalContent: any;


  9. private mouseDownX: number = 0;

  10. private mouseDownY: number = 0;

  11. private deltaX: number = 0;

  12. private deltaY: number = 0;

  13. private sumX: number = 0;

  14. private sumY: number = 0;


  15. constructor(props: ModalProps) {

  16. super(props);

  17. this.simpleClass = Math.random()

  18. .toString(36)

  19. .substring(2);

  20. }


  21. handleMove = (event: any) => {

  22. const deltaX = event.pageX - this.mouseDownX;

  23. const deltaY = event.pageY - this.mouseDownY;


  24. this.deltaX = deltaX;

  25. this.deltaY = deltaY;


  26. this.modalContent.style.transform = `translate(${deltaX + this.sumX}px, ${deltaY + this.sumY}px)`;

  27. };


  28. initialEvent = (visible: boolean) => {

  29. const { title } = this.props;

  30. if (title && visible) {

  31. setTimeout(() => {

  32. window.removeEventListener('mouseup', this.removeUp, false);


  33. this.contain = document.getElementsByClassName(this.simpleClass)[0];

  34. this.header = this.contain.getElementsByClassName('ant-modal-header')[0];

  35. this.modalContent = this.contain.getElementsByClassName('ant-modal-content')[0];


  36. this.header.style.cursor = 'all-scroll';

  37. this.header.onmousedown = (e: MouseEvent<HTMLDivElement>) => {

  38. this.mouseDownX = e.pageX;

  39. this.mouseDownY = e.pageY;

  40. document.body.onselectstart = () => false;

  41. window.addEventListener('mousemove', this.handleMove, false);

  42. };


  43. window.addEventListener('mouseup', this.removeUp, false);

  44. }, 0);

  45. }

  46. };


  47. removeMove = () => {

  48. window.removeEventListener('mousemove', this.handleMove, false);

  49. };


  50. removeUp = () => {

  51. document.body.onselectstart = () => true;


  52. this.sumX = this.sumX + this.deltaX;

  53. this.sumY = this.sumY + this.deltaY;


  54. this.removeMove();

  55. };


  56. componentDidMount() {

  57. const { visible = false } = this.props;

  58. this.initialEvent(visible);

  59. }


  60. componentWillUnmount() {

  61. this.removeMove();

  62. window.removeEventListener('mouseup', this.removeUp, false);

  63. }


  64. render() {

  65. const { children, wrapClassName, ...other } = this.props;

  66. const wrapModalClassName = wrapClassName ? `${wrapClassName} ${this.simpleClass}` : `${this.simpleClass}`;

  67. return (

  68. <AntdModal

  69. {...other}

  70. wrapClassName={wrapModalClassName}

  71. >{children}</AntdModal>

  72. );

  73. }

  74. }

在 AntDraggableModal
 组件的构造函数中,随机生成一个 simpleClass
 字符串,传递给 AndModal
 组件的 wrapClassName
 属性,这样做的目的主要有两个:

  1. 便于通过 simpleClass
     类来定位弹窗位置

  2. 当有多个弹窗时,可以通过 simpleClass
     类来区分不同的弹窗,实现多层弹窗拖拽功能

用法上需要注意的一点是:

  1. {this.state.visible && (

  2. <AntdDraggableModal

  3. title="Basic Modal"

  4. visible={this.state.visible}

  5. onOk={this.handleOk}

  6. onCancel={this.handleCancel}

  7. >

  8. <p>Some contents...</p>

  9. <p>Some contents...</p>

  10. <p>Some contents...</p>

  11. <Button onClick={() => this.setState({ visible2: true })}>打开弹窗2</Button>

  12. </AntdDraggableModal>

  13. )}

必须要这么写,因为每次弹窗关闭的时候是不会自动销毁的,也就是说弹窗关闭再打开的时候我们希望弹窗的位置会重新被初始化。

总结

关于 ant-design
 Mmodal
 的可拖拽封装就介绍到这里,组件我已经发布到 npm 上面了,感兴趣的同学欢迎安装使用,Have a nice weekend !😊更多精彩内容欢迎关注我的公众号!


文章转载自前端架构师笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论