原生JS实现鼠标拖动改变dom滚动条位置

有时页面内容过多时会同时出现横向和纵向滚动条, 鼠标拖动滚动条感觉操作有些繁琐, 所以尝试直接拖动dom来实现拖动滚动条同样的效果

  • dom结构如下
<style>
  .father {
    height: 50vh;
    width: 70vw;
    overflow: auto;
    border: 1px solid;
  }
  
  .child {
    width: 500vw;
    height: 500vh;
  }
</style>
...
<body>
  <div class="father">
    <div class="child"></div>
  </div>
</body>
 

那么首先理清思路

  • 同时监听父节点的mousedown事件和mousemove事件
  • 当按下和移动同时触发时, 计算X和Y移动的距离
  • 将移动的距离应用到滚动条上

那么, 上代码!

1. 获取父元素节点

let father = document.querySelector('.father');
 

2. 定义需要用到的变量

// 判断鼠标是否按下
let isMouseDown = false;
// 记录Y轴滚动距离
let scrollTop = 0;
// 记录X轴滚动距离
let scrollLeft = 0;
// 记录鼠标落点X坐标
let startX = 0;
// 记录鼠标落点Y坐标
let startY = 0;
 

3. 监听鼠标按下事件

father.addEventListener('mousedown', e => {
  // 修改按下状态
  isMouseDown = true;
  // 记录按下鼠标的位置, 用于计算鼠标的移动距离
  startX = e.offsetX;
  startY = e.offsetY;
});
 

4. 监听鼠标移动事件

father.addEventListener('mousemove', e => {
  // 判断鼠标移动时是否处于按下状态
  if (isMouseDown) {
    // 获取鼠标按下后移动的距离
    let offsetX = e.offsetX - startX;
    let offsetY = e.offsetY - startY;
    // PS: 需要注意的是当鼠标向上移动时, 滚动条应该向下移动, 所以这里都是减去的移动距离
    scrollTop = scrollTop - offsetY;
    scrollLeft = scrollLeft - offsetX;

    // TODO

    // 将计算后的距离赋值给滚动条
    father.scrollTop = scrollTop;
    father.scrollLeft = scrollLeft;
  }
}
 

5. 当鼠标抬起时修改状态

father.addEventListener('mouseup', () => {
  isMouseDown = false;
})
 

但是当我们使用时很快会发现一个问题, 就是当滚动条滑块移动到端点时, 计算距离依然会继续累加, 导致的结果就是, 当累加距离超过极限时, 向反向移动鼠标,滑块不会立即移动. 所以对上述代码进行修改

PS1: Step2中添加计算极限距离的变量

// 横向可移动的最大距离
let limitX = father.scrollWidth - father.offsetWidth;
// 纵向可移动的最大距离
let limitY = father.scrollHeight - father.offsetHeight;
 

PS2: Step4中添加判断

...
// TODO
if (scrollTop >= limitY) {
  // 当滑块移动到底端时
  scrollTop = limitY;
} else if (scrollTop <= 0) {
  // 当滑块移动到顶端时
  scrollTop = 0;
}

if (scrollLeft >= limitX) {
  // 当滑块移动到左侧时
  scrollLeft = limitX;
} else if (scrollLeft  <= 0) {
  // 当滑块移动到右侧时
  scrollLeft = 0;
}
...
 
(0)
上一篇 2021年6月4日 下午1:36
下一篇 2021年6月4日 下午1:50

相关推荐

发表回复

登录后才能评论