有时页面内容过多时会同时出现横向和纵向滚动条, 鼠标拖动滚动条感觉操作有些繁琐, 所以尝试直接拖动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;
}
...
PS3:
因为考虑到滑动时的流畅问题, 监听事件并未添加节流器, 如果有任何优化建议, 希望可以告知一下.