Ant Design Vue Modal组件增加拖拽移动和调整大小的功能

3,198 阅读2分钟

ant design vue的弹窗组件没有移动和调整大小功能,使用起来略有不便,根据网上搜索到的代码示例进行了完善,实现该功能。以防忘记,记录如下:

拖拽移动

弹框拖拽移动的功能可以参照ant design vue的最后一个示例

对话框 Modal - Ant Design Vue (antdv.com)

拖拽宽高变化

拖拽宽高变化功能代码如下:

    <!--其他参照antdv官网的modal的最后一个示例-->
    <template #modalRender="{ originVNode }" v-if="moveable">
      <div
        :style="transformStyle"
        :class="isFullScreen ? 'full-screen-content' : ''"
        ref="modalRef"
      >
        <component :is="originVNode" />
        <!--主要增加这个元素用于拖拽的时候显示能够变化的大小-->
        <div class="modal-drag-position"></div>
      </div>
    </template>
    // 弹框显示的时候,调用调整调整弹框大小的函数
    // useModalDrag函数的maxHeight, maxWidth, changePosition是给modal适应当前container位置使用的,
    // 如果是挂载到body上可以不用这几个参数
    watch(
      () => props.visible,
      () => {
        if (props.visible) {
          nextTick(() => {
            useModalDrag(modalRef, isFullScreen, maxHeight, maxWidth, changePosition);
          });
        }
      },
    );
    // 浏览器size发生变化的时候也调用这个函数
    window.addEventListener('resize', () => {
      nextTick(() => {
        useModalDrag(modalRef, isFullScreen, maxHeight, maxWidth, changePosition);
      });
    });
import type { Ref } from 'vue';
export const useModalDrag = (modalRef: Ref<any>, isFullScreen, maxHeight, maxWidth, callback) => {
  const widthDom = modalRef.value;
  const dragDom = widthDom?.closest('.ant-modal-wrap');
  // const widthDom = el.closest('.ant-modal');
  const widthBodyDom = widthDom?.querySelector('.ant-modal-body');
  const sizeChangeDom = widthDom?.querySelector('.modal-drag-position');
  const headerDom = widthDom?.querySelector('.ant-modal-header');
  const footerDom = widthDom?.querySelector('.ant-modal-footer');
  if (!widthDom || !dragDom || !widthBodyDom || !sizeChangeDom) return;
  const minWidth = widthDom.clientWidth < 300 ? widthDom.clientWidth : 300;
  const minHeight = widthDom.clientHeight < 200 ? widthDom.clientHeight : 200;
  maxHeight.value = dragDom.clientHeight;
  maxWidth.value = dragDom.clientWidth;
  sizeChangeDom.style.width = '100%';
  sizeChangeDom.style.height = '100%';

  dragDom.onmousemove = function (e) {
    // e.stopPropagation();
    if (isFullScreen.value) return;
    const rect = widthDom.getBoundingClientRect();
    if (e.clientX > widthDom.clientWidth + rect.left - 10) {
      widthDom.style.cursor = 'e-resize';
    } else if (e.clientY > widthDom.clientHeight + rect.top - 10) {
      widthDom.style.cursor = 's-resize';
    } else {
      widthDom.style.cursor = 'default';
      widthDom.onmousedown = null;
    }
    if (
      e.clientX > widthDom.clientWidth + rect.left - 10 &&
      e.clientY > widthDom.clientHeight + rect.top - 10
    ) {
      widthDom.style.cursor = 'se-resize';
    }

    dragDom.onmousedown = e => {
      if (isFullScreen.value) return;
      const rect = widthDom.getBoundingClientRect();
      dragDom.style.userSelect = 'none';
      let moveDirection = '';
      const initClientHeight = widthDom.clientHeight;
      let heightChange = 0;
      let widthNeedChange = false;
      let heightNeedChange = false;
      if (
        e.clientX > widthDom.clientWidth + rect.left - 10 &&
        e.clientX <= widthDom.clientWidth + rect.left
      ) {
        // 左右移动
        moveDirection = 'x';
      }

      if (
        e.clientY > widthDom.clientHeight + rect.top - 10 &&
        e.clientY <= widthDom.clientHeight + rect.top
      ) {
        // 上下移动
        moveDirection = 'y';
      }

      if (
        e.clientX > widthDom.clientWidth + rect.left - 10 &&
        e.clientX <= widthDom.clientWidth + rect.left &&
        e.clientY > widthDom.clientHeight + rect.top - 10 &&
        e.clientY <= widthDom.clientHeight + rect.top
      ) {
        // 上下左右移动
        moveDirection = 'xy';
      }

      if (moveDirection == '') {
        return;
      }

      const onMouseup = () => {
        if (sizeChangeDom.style.width && widthNeedChange) {
          widthDom.style.width = sizeChangeDom.style.width;
        }
        if (heightChange && heightNeedChange) {
          // widthBodyDom.style.height = widthBodyDom.clientHeight + heightChange + 'px';
          let height =
            sizeChangeDom.clientHeight -
            (headerDom?.clientHeight || 0) -
            (footerDom?.clientHeight || 0);
          const maxHeight = Number(widthBodyDom.style.maxHeight?.replace('px', '') || '0');
          if (height > maxHeight) {
            height = maxHeight;
            sizeChangeDom.style.height =
              maxHeight + (headerDom?.clientHeight || 0) + (footerDom?.clientHeight || 0) + 'px';
          }
          widthBodyDom.style.height = height + 'px';
          callback();
        }
        dragDom.removeEventListener('mousemove', onMousemove);
        sizeChangeDom.style.zIndex = -1;
        moveDirection = '';
        heightChange = 0;
        widthNeedChange = false;
        heightNeedChange = false;
        document.onmouseup = null;
      };
      const onMousemove = e => {
        // e.stopPropagation();
        if (isFullScreen.value) return;
        if (moveDirection === 'x') {
          sizeChangeDom.style.zIndex = 1;
          let width = e.clientX - rect.left;
          width = width >= minWidth ? width : minWidth;
          sizeChangeDom.style.width = width + 'px';
          widthNeedChange = true;
          // console.info('onMousemove', sizeChangeDom.style.width);
        } else if (moveDirection === 'y') {
          sizeChangeDom.style.zIndex = 1;
          let height = e.clientY - rect.top;
          height = height >= minHeight ? height : minHeight;
          // 找到移动后的变化
          heightChange = height - initClientHeight;
          sizeChangeDom.style.height = height + 'px';
          heightNeedChange = true;
          // console.info('onMousemove', sizeChangeDom.style.height);
        }
        if (moveDirection === 'xy') {
          sizeChangeDom.style.zIndex = 1;
          let width = e.clientX - rect.left;
          width = width >= minWidth ? width : minWidth;
          sizeChangeDom.style.width = width + 'px';
          widthNeedChange = true;

          sizeChangeDom.style.zIndex = 1;
          let height = e.clientY - rect.top;
          height = height >= minHeight ? height : minHeight;
          // 找到移动后的变化
          heightChange = height - initClientHeight;
          sizeChangeDom.style.height = height + 'px';
          heightNeedChange = true;
        }
        document.onmouseup = onMouseup;
      };
      dragDom.onmouseup = onMouseup;
      dragDom.addEventListener('mousemove', onMousemove);
    };
  };
};

.modal-drag-position {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.1);
  z-index: -1;
}