当前位置:编程学习 > > 正文

vue将弹框抽离成组件(vue3 可拖动的左右面板分割组件实现)

时间:2022-01-17 01:50:17类别:编程学习

vue将弹框抽离成组件

vue3 可拖动的左右面板分割组件实现

最近在使用vue的时候,遇到一个需求,实现左右li可通过中间部分拖拽调整宽度,本文就整理一下,分享给大家,具体如下:

效果图

vue将弹框抽离成组件(vue3 可拖动的左右面板分割组件实现)

分解组件

整体使用flex布局

左侧面板

右侧面板

vue将弹框抽离成组件(vue3 可拖动的左右面板分割组件实现)

入参分解

props

slots

具体实现

如何拖动呢?

在左侧面板与右侧面板之间添加一个隐藏的盒子,我将这个盒子隐藏在box-shadow之中。具体事件放在这个li中实现

  • <li id="line" class="w-2 cursor-move hidden md4:block"onMousedown={hnadleMouseDown}>
    </li>
    
  • 事件监听

  •     const hnadleMouseDown = (evt: MouseEvent) => {
          /* 获取起始点位,并存储 */
          let { pageX, pageY } = evt;
          basePosition.pageX = pageX;
          basePosition.pageY = pageY;
          /* 监听鼠标的移动事件 */
          document.addEventListener("mousemove", handleMouseMove);
          document.addEventListener("mouseup", handleMouseUp);
        };
        const handleMouseMove = evt => {
          /* 阻止浏览器默认事件,防止触发浏览器的手势功能 */
          evt.preventDefault();
          /* 设置定时器,防止dom多次回流 */
          clearTimeout(timer.value);
          timer.value = setTimeout(() => {
            let { pageX } = evt;
            const baseli = document.querySelector(".right-border-shadow");
            /* 处理宽度,是否处于最大值/最小值之间 */
            let baseWidth: Number | undefined =
              Number(baseli?.clientWidth) + (pageX - basePosition.pageX);
            baseWidth =
              baseWidth > Number(props?.maxWidth) ? props.maxWidth : baseWidth;
            baseWidth =
              Number(baseWidth) < Number(props?.minWidth)
                ? props.minWidth
                : baseWidth;
            baseli?.setAttribute("style", `width:${baseWidth}px`);
            /* emit宽度改变的事件 */
            ctx.emit("drugend");
            /* 存储到store */
            setStore(baseWidth);
          }, 50);
        };
        const handleMouseUp = evt => {
          /* 结束拖动之后,取消事件监听,并emit出最终宽度 */
          const width = document.querySelector(".right-border-shadow")?.clientWidth;
          document.removeEventListener("mousemove", handleMouseMove);
          document.removeEventListener("mouseup", handleMouseUp);
          ctx.emit("drugend", width);
        };
    
    
  • 宽度处理

  • style={`width:${
                store.get("split-width")
                  ? store.get("split-width")
                  : props.minWidth
                  ? props.minWidth
                  : 384
              }px`}
    
    
  • 优化

    手动改变浏览器视窗宽度

  • nextTick(() => {
            ctx.emit("load", ctx);
            MutationObserver = window.MutationObserver;
            if (MutationObserver) {
              /* 监听浏览器的窗口变化,在部分情况下需要这个api */
              mo = new MutationObserver(function() {
                const __wm = document.querySelector("#rezie-id");
                // 只在__wm元素变动才重新调用 __canvasWM
                if (!__wm) {
                  // 避免一直触发
                  mo.disconnect();
                  mo = null;
                  ctx.emit("resize");
                }
              });
              mo.observe(document.querySelector("#rezie-id"), {
                attributes: true,
                subtree: true,
                childList: true,
              });
            }
          });
    
    
  • 未生效,求指点

    bug

    父组件的onMounted钩子中获取子元素的slot元素节点报错,为null。目前的解决办法是在子组件的onMounted钩子中抛出一个load事件,父组件使用onLoad去处理接下来的逻辑。

    git地址

    仓库地址
    预览地址

    到此这篇关于vue3 可拖动的左右面板分割组件实现的文章就介绍到这了,更多相关vue3 可拖动左右分割面板内容请搜索开心学习网以前的文章或继续浏览下面的相关文章希望大家以后多多支持开心学习网! 

    上一篇下一篇

    猜您喜欢

    热门推荐