實現可拖拽側邊欄

效果演示圖

可拖拽側邊欄的使用情況非常多啊,部落格園後台管理左側邊欄就可以拖拽喲!廢話不多說,本隨筆實現的可拖拽側邊欄效果演示圖如下:

image

HTML 程式碼

<div class="container">
  <div class="left">
    <div class="resize-bar"></div>
  </div>
  <div class="right">
    <div class="resize-bar"></div>
  </div>
</div>

CSS 程式碼

html,
body {
  display: flex;
  justify-content: center;
  align-items: center;
  align-content: center;
  padding: 0 !important;
  margin: 0 !important;
}

.container {
  width: 80vw;
  height: 100vh;
  display: flex;
  justify-content: space-between;
  align-items: center;
  align-content: center;
}

.left {
  position: relative;
  width: 100px;
  height: 100%;
  background-color: rgb(160, 212, 233);
}

.left .resize-bar {
  position: absolute;
  top: 0;
  left: 100px;
  width: 3px;
  height: 100%;
  opacity: 0;
}

.left .resize-bar:hover {
  cursor: col-resize;
  opacity: 1;
  background-color: rgb(210, 85, 50);
}

.right {
  position: relative;
  width: 100px;
  height: 100%;
  background-color: rgb(36, 107, 214);
}

.right .resize-bar {
  position: absolute;
  top: 0;
  right: 100px;
  width: 3px;
  height: 100%;
  opacity: 0;
}

.right .resize-bar:hover {
  cursor: col-resize;
  opacity: 1;
  background-color: rgb(211, 36, 164);
}

JS 程式碼

拖拽右側邊欄

image

如上圖,紅色方框是 container 的區域,我們的側邊欄可移動範圍也是在 container 移動範圍內。

滑鼠按住不放拖拽右側邊欄,右側邊欄的寬度此時是逐漸增大的趨勢。滑鼠移動多少 px 根據用戶移動滑鼠的速率決定。假如,滑鼠移動到 1200px 的位置,右側邊欄左邊緣往左移動 startWidth 個像素點的距離。那麼,startWidth 該怎麼計算呢?

初始階段,右側邊欄邊緣(startWidth)應該是整個 container 的寬度減去右側邊欄的寬度。假如,container 的寬度是 1355 px,右側邊欄的寬度是 100 px;那麼,startWidth = 1355px – 100px = 1255px。此時的滑鼠移動到 1200px,那麼右側邊欄應該從邊緣部分起移動 1255px – 1200px = 55px 的距離。也就是說,原來的右側邊欄寬度 100px 應該變成 100px + 55px = 155px。

const container = document.querySelector(".container");
const right = document.querySelector(".right");
const rightResizeBar = document.querySelector(".right .resize-bar");

function moveRightBar(event) {
  setTimeout(() => {
    let startWidth = container.clientWidth - right.clientWidth;
    let shiftWidth = startWidth - event.pageX + container.offsetLeft + right.clientWidth;
    right.style.width = shiftWidth + "px";
    rightResizeBar.style.right = shiftWidth + "px";
  }, 200);
}

這裡要特別聲明,pageX、clientX 都是一樣的數值,用哪個都可以。而且,程式碼中還加了一個 container.offsetLeft。因為我們的 container 可能是被 flex 布局設置了居中,那麼此時 container 與瀏覽器窗口有一個 left 偏移量,所以需要加上這個 left 以保證移動距離的準確性。如效果演示圖中,container 並沒有緊挨著瀏覽器窗口的左邊邊緣處。

添加監聽器

滑鼠點擊到 rightResizeBar 元素時,就應該開啟整個 container 的 mousemove 事件:

// 1. 滑鼠按下 rightResizeBar 元素,開啟 container 的事件監聽
rightResizeBar.addEventListener("mousedown", () => {
  container.addEventListener("mousemove", moveRightBar);
});

// 2. 當滑鼠從 rightResizeBar 放下時,取消監聽
rightResizeBar.addEventListener("mouseup", () => {
  container.removeEventListener("mousemove", moveRightBar);
});

// 3. 當滑鼠從 container 範圍內放下時,取消監聽
container.addEventListener("mouseup", () => {
  container.removeEventListener("mousemove", moveRightBar);
});

滑鼠放下時,清除事件監聽。上面的程式碼中 rightResizeBar 元素和 container 都清除了 container 的 mousemove 事件,這是為了確保清除乾淨才這樣做的。

拖拽左側邊欄

左側邊欄就非常簡單了,因為滑鼠的移動與瀏覽器的 x、y 有關係,所以,左側邊欄的右邊緣處移動正符合上面右側邊欄那樣的 startWidth,而且不需要計算。但是,必須要加上 container 的 left 偏移量,同上。

function moveLeftBar(event) {
  setTimeout(() => {
    let shiftWidth = event.pageX - container.offsetLeft;
    left.style.width = shiftWidth + "px";
    leftResizeBar.style.left = shiftWidth + "px";
  }, 200);
}

添加事件監聽

leftResizeBar.addEventListener("mousedown", () => {
  container.addEventListener("mousemove", moveLeftBar);
});

leftResizeBar.addEventListener("mouseup", () => {
  container.removeEventListener("mousemove", moveLeftBar);
});

container.addEventListener("mouseup", () => {
  container.removeEventListener("mousemove", moveLeftBar);
});

源碼倉庫