1. 程式人生 > 程式設計 >vue3 可拖動的左右面板分割元件實現

vue3 可拖動的左右面板分割元件實現

最近在使用vue的時候,遇到一個需求,實現左右div可通過中間部分拖拽調整寬度,本文就整理一下,分享給大家,具體如下:

效果圖

vue3 可拖動的左右面板分割元件實現

分解元件

整體使用flex佈局

左側面板

  • 面板的具體內容通過slot具名插槽傳入。
  • title通過prop傳入
  • 可拖動,為了保證內容樣式不會被拖動所破壞,對面板的寬度設定最大值/最小值

右側面板

  • 右側面板寬度隨著左側面板的寬度變化而變化,此處需注意,內容的寬度使用flex-auto自動適應。
  • 需要做移動端的自適應。
  • 自適應使用tailwind的媒體查詢

vue3 可拖動的左右面板分割元件實現

入參分解

props

  • @param {Number} maxWidth 最大寬度
  • @param {Number} minWidth 最小寬度
  • @param {String} leftTitle 左標題
  • @param {Striwww.cppcns.comng} rightTitle 右標題?
  • @param {Boolean} sotoreage 是否儲存與localstorege

slots

  • left-content {Element} 左側內容
  • right-content {Element} 右側內容

具體實現

如何拖動呢?

在左側面板與右側面板之間新增一個隱藏的盒子,我將這個盒子隱藏在box-shadow之中。具體事件放在這個div中實現

<div id="line" class="w-2 cursor-move hidden md4:block"onMousedown={hnadleMouseDown}>
</div>

事件監聽

    const hnadleMouseDown = (evt: MouseEvent) => {
      /* 獲取起始點位,並存儲 */
      let { pageX,pageY } = evt;
      basePosition.pageX = pageX;
      basePosition.pageY = pageY;
      /* 監聽滑鼠的移動事件 */
      dowww.cppcns.com
cument.addEventListener("mousemove",handleMouseMove); document.addEventListener("mouseup",handleMouseUp); }; const handleMouseMove = evt => { /* 阻止瀏覽器預設事件,防止觸發瀏覽器的手勢功能 */ evt.preventDefault(); /* 設定定時器,防止dom多次迴流 */ clearTimeout(timer.value); timer.value = setTimeout(() => { let { pageX } = evt; const baseDiv = document.querySelector(".right-border-shadow"); /* 處理寬度,是否處於最大值/最小值之間 */ let baseWidth: Number | undefined = Number(baseDiv?http://www.cppcns.com.clientWidth) + (pageX - basePosition.pageX); baseWidth = baseWidth > Number(props?.maxWidth) ? props.maxWidth : baseWidth; baseWidth = Number(baseWidth) < Number(props?.minWidth) ? props.minWidth : baseWidth; baseDiv?.setAttribute("style",`width:${baseWidth}px`); /* emit寬度改變的事件 */ ctx.emit("drugend"); /* 儲存到store */ setStore(baseWidth); },50); }; const handleMouseUp = evt => { /* 結束拖動之後,取消事件監聽,並emit出最終寬度 */ const width = documentwww.cppcns.com.querySelector(".right-border-shadow")?.clientWidth; document.removeEventListhttp://www.cppcns.comener("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 可拖動左右分割面板內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!