实现可拖拽侧边栏

效果演示图

可拖拽侧边栏的使用情况非常多啊,博客园后台管理左侧边栏就可以拖拽哟!废话不多说,本随笔实现的可拖拽侧边栏效果演示图如下:

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);
});

源码仓库