vue项目实现el-popover弹窗拖拽位置以及实现弹窗的拖拽调整大小功能

本文介绍了如何在Vue项目中实现el-popover弹窗的拖拽功能和通过拖动边框改变弹窗大小的功能。通过自定义指令`popover`和`popoverDragWidth`,分别实现了弹窗的拖动及拖动边框调整大小,同时设置了拖动范围限制和最小尺寸约束。
记录一下vue项目实现el-popover弹窗拖拽以及拖动边框实现弹框拖大拖小。旨在记录,不足之处请多多指教。

1、popover弹窗拖拽的实现

具体实现的步骤如下:

//自定义指令,名为"popover",用于实现拖拽功能,要使用的组件直接v-popover
Vue.directive('popover', {
  bind(el, binding, vnode, oldVnode) {
      // 1、在bind钩子函数中获取弹窗标题栏元素(dialogHeaderEl)、弹窗底部元素(dialogFootEl)和弹窗内容元素(dragDom)。
      const dialogHeaderEl = el.querySelector('.el-pagination'); // 获取弹窗标题栏元素
      const dragDom = el.querySelector('.el-popover'); // 获取弹窗内容元素
      const that=vnode.context;
      
      // 2、判断是否成功获取到弹窗内容元素,若未获取到则不绑定拖拽功能。
      if(!dragDom) return; // 如果没有找到弹窗内容元素,则不绑定拖拽

      // 3、获取弹窗内容元素的样式属性(sty),包括位置等信息。
      // 获取弹窗内容元素的样式属性
      const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null);

      // 4、定义moveDown函数,该函数用于处理鼠标按下事件,实现拖拽效果。
      const moveDown= (e) => {
          // 鼠标按下,计算当前元素距离可视区的距离
          const disX = e.clientX - dialogHeaderEl.offsetLeft;
          const disY = e.clientY - dialogHeaderEl.offsetTop;

          // 获取到的值带px 正则匹配替换
          let styL, styT;

          // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
          if(sty.left.includes('%')) {
              styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100);
              styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100);
          }else {
              styL = +sty.left.replace(/\px/g, '');
              styT = +sty.top.replace(/\px/g, '');
          };

          // 5、在document.onmousemove事件处理函数中计算当前元素的移动距离,并限制移动范围在窗口可视区域内。
          document.onmousemove = function (e) {
              // 通过事件委托,计算移动的距离
              let l = e.clientX - disX + styL;
              let t = e.clientY - disY + styT;

              // 设置边界限制
              let minL=-((document.documentElement.clientWidth-dragDom.offsetWidth)*0.5+dragDom.offsetWidth-50)
              let maxL=(document.documentElement.clientWidth-dragDom.offsetWidth)*0.5+dragDom.offsetWidth-50
              let minT=-document.documentElement.clientHeight*0.1
              let maxT=document.documentElement.clientHeight - dragDom.offsetHeight-document.documentElement.clientHeight*0.1+dragDom.offsetHeight-50

              if (l <= minL) {
                l = minL
              } else if (l >=maxL ){
                l = maxL
              }

              if (t <=minT ) {
                t = minT;
              } else if (t >= maxT){
                t = maxT
              }

              t = t > minT ? t : minT;

              // 移动当前元素
              dragDom.style.left = `${l}px`;
              dragDom.style.top = `${t}px`;

              //将此时的位置传出去
              //binding.value({x:e.pageX,y:e.pageY})
          };

          // 6、在document.onmouseup事件处理函数中清除事件监听,结束拖拽操作。
          document.onmouseup = function (e) {
              document.onmousemove = null;
              document.onmouseup = null;
          };
      }
      // 7、将moveDown函数绑定到弹窗标题栏元素的onmousedown事件上,当鼠标按下标题栏时触发拖拽。
      dialogHeaderEl.onmousedown=moveDown;
  }
})

2、popover弹窗拖拽调整大小功能的实现

// 自定义指令名为"popoverDragWidth"
Vue.directive('popoverDragWidth', {
  bind(el, binding, vnode, oldVnode) {
    // 定义最小高度和最小宽度
    const minH = 300;
    const minW = 500;
    // 定义边框大小
    const borderSize = 10;
    // 初始化起始位置和尺寸
    let startX = 0;
    let startY = 0;
    let startWidth = 0;
    let startHeight = 0;
    // 获取弹窗内容元素
    const dragDom = el.querySelector('.el-popover');
    // 初始化是否正在调整大小的标志
    let isResizing = false;
    // 获取Vue实例对象
    const that = vnode.context;
    // 定义垂直和水平调整大小的光标样式
    const handleCursorVertical = "ns-resize";
    const handleCursorHorizontal = "ew-resize";

    // 设置初始光标样式为垂直调整大小
    dragDom.style.cursor = 'ns-resize';

    // 监听鼠标移动事件,根据光标位置确定光标样式,并修改调整大小标志
    dragDom.addEventListener('mousemove', e => {
        let h = dragDom.clientHeight, w = dragDom.clientWidth;
        let isOnHorizontalBorder = w - e.offsetX < borderSize, isOnVerticalBorder = h - e.offsetY < borderSize;

        // 根据光标位置设置光标样式
        if (isOnHorizontalBorder) dragDom.style.cursor = handleCursorHorizontal;
        if (isOnVerticalBorder)  dragDom.style.cursor = handleCursorVertical;
        if (isOnHorizontalBorder && isOnVerticalBorder) dragDom.style.cursor = 'crosshair';
        if (!isOnHorizontalBorder && !isOnVerticalBorder) dragDom.style.cursor = '';
        
        // 修改调整大小标志
        if (isOnHorizontalBorder || isOnVerticalBorder) isResizing = true;
    })

    // 监听鼠标按下事件,保存起始位置和尺寸,并添加鼠标移动和鼠标释放事件监听器
    dragDom.addEventListener("mousedown", e => {
      // 获取弹窗内容元素的位置和尺寸信息
      const rect = dragDom.getBoundingClientRect();
      startX = e.clientX;
      startY = e.clientY;
      startWidth = rect.width;
      startHeight = rect.height;

      // 如果不处于调整大小状态,直接返回
      if(!isResizing) return;
      
      // 添加鼠标移动和鼠标释放事件监听器
      document.addEventListener("mousemove", resizeWidthHeight, false);
      document.addEventListener("mouseup", removeResize, false);
    });

    // 调整元素的宽度和高度
    function resizeWidthHeight(e) {
      if (!isResizing) return;

      // 计算新的宽度和高度
      let width = startWidth + e.clientX - startX;
      let height = startHeight + e.clientY - startY;
      
      // 如果宽度小于最小宽度,则使用最小宽度
      if(width < minW) width = minW;
      // 如果高度小于最小高度,则使用最小高度
      if(height < minH) height = minH;
      
      // 设置元素的新宽度和高度
      dragDom.style.width = `${width}px`;
      dragDom.style.height = `${height}px`;
    }

    // 移除调整大小事件监听器,并重置光标样式,并通过 Vue 实例传递元素新的尺寸信息
    function removeResize() {
      isResizing = false;
      document.removeEventListener("mousemove", resizeWidthHeight, false);
      document.removeEventListener("mouseup", removeResize, false);
      dragDom.style.cursor = '';
      
      // 如果存在 setTablewH 方法,则调用该方法并传递元素位置和尺寸信息
      that.setTablewH && that.setTablewH(dragDom.getBoundingClientRect());
    }
  }
});

具体实现的步骤如下:

1、在bind钩子函数中,定义最小高度(minH)和最小宽度(minW)的值,以及边框大小(borderSize)。
2、初始化起始位置和尺寸的变量,用于记录拖拽调整大小的起始状态。
3、获取弹窗内容元素(dragDom)。
4、初始化是否正在调整大小的标志(isResizing)。
5、获取Vue实例对象(that)。
6、定义垂直和水平调整大小的光标样式(handleCursorVertical和handleCursorHorizontal)。
7、设置初始光标样式为垂直调整大小。
8、监听鼠标移动事件,根据光标位置确定光标样式,并修改调整大小标志。
9、监听鼠标按下事件,保存起始位置和尺寸,并添加鼠标移动和鼠标释放事件监听器。
10、在鼠标移动事件处理函数resizeWidthHeight中计算新的宽度和高度,并限制最小宽度和最小高度。
11、在鼠标释放事件处理函数removeResize中移除调整大小事件监听器,重置光标样式,并通过Vue实例方法setTablewH传12、递元素新的位置和尺寸信息。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你怎么在吐泡泡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值