鼠标相对位移与绝对位移

一、方式展示

以下两段代码都是在鼠标移动过程中改变元素宽度,不同之处是第一种在移动过程中更新初始位置和宽度,处理的是增量位移,第二种是只在鼠标按下时记录初始位置,处理的是绝对位移。

第一种
1const getElePos = (ele) => {
2      const pos = ele.getBoundingClientRect();
3      return pos;
4    }
5
6    handleEle.addEventListener('mousedown', (e) => {
7      startX = e.clientX;
8      isDragging = true;
9
10    });
11
12    // 每次拖拽都更新鼠标位置和宽度
13
14    document.addEventListener('mousemove', (e) => {
15      
16      if (!isDragging) return;
17      const dx = e.clientX - startX;
18
19      const containerWidth = wrapperEle.offsetWidth;
20      const dragBarWidth = handleEle.offsetWidth;
21
22      const leftPos = getElePos(panelLeftEle);
23      const rightPos = getElePos(panelRightEle)
24
25      console.log(leftPos.width, dx);
26      const leftWidth = leftPos.width + dx;
27      const rightWidth = rightPos.width - dx;
28
29      panelLeftEle.style.width = `${leftWidth}px`;
30      panelRightEle.style.width = `${rightWidth}px`;
31      startX = e.clientX
32
33    });
34
35    document.addEventListener('mouseup', () => {
36      isDragging = false;
37    });
第二种
1handleEle.addEventListener('mousedown', (e) => {
2      startX = e.clientX;
3      isDragging = true;
4
5      const leftPos = getElePos(panelLeftEle);
6      const rightPos = getElePos(panelRightEle)
7      // 只在鼠标按下时更新鼠标位置
8      startLeftEleWidth = leftPos.width;
9      startRightEleWidth = rightPos.width;
10
11    });
12   
13  
14    document.addEventListener('mousemove', (e) => {
15      if (!isDragging) return;
16      const dx = e.clientX - startX;
17
18      const containerWidth = wrapperEle.offsetWidth;
19      const dragBarWidth = handleEle.offsetWidth;
20
21      const leftPos = getElePos(panelLeftEle);
22      const rightPos = getElePos(panelRightEle)
23
24      const leftWidth = startLeftEleWidth + dx;
25      const rightWidth = startRightEleWidth - dx;
26
27      panelLeftEle.style.width = `${leftWidth}px`;
28      panelRightEle.style.width = `${rightWidth}px`;
29
30    });
31
32    document.addEventListener('mouseup', () => {
33      isDragging = false;
34    });

二、方式对比

第一种在鼠标移动过程中会出现鼠标位置与拖拽条位置不匹配的问题原因主要有以下几点:

  1. 浏览器对小像素数的处理机制

浏览器渲染时会对小数像素进行舍入处理,主要机制包含亚像素渲染,浏览器内部使用浮点数计算布局,但最终渲染时会将元素对齐到物理像素网格。增量位移中偏移量出现小数的可能性和频率更大,移动越久,误差累积越多。

1// 假设:
2leftPos.width = 100.4px → 实际可能渲染为100px
3dx = 10.6px → 实际可能移动10px
4leftWidth = 100.4 + 10.6 = 111px
5但实际渲染:
6100px + 10px = 110px → 出现1px偏差
1// 连续多次小位移计算示例
2let width = 100;
3width += 0.3; // 100.3 → 渲染为100px
4width += 0.3; // 100.6 → 渲染为101px
5width += 0.3; // 100.9 → 渲染为101px
6// 实际总位移:0.9px → 渲染总变化:1px
  1. 浏览器事件系统

根据W3C标准,鼠标事件坐标通常返回整数(CSS像素单位),底层原因时硬件限制、性能优化以及历史兼容性。由于只返回整数,慢速移动时可能连续获取相同值,快速移动时会出现较大跳跃。

1// 如果每次只捕获整数位移:
2// 理论路径:0.3 + 0.3 + 0.3 = 0.9px
3// 实际捕获:0 + 0 + 1 = 1px (误差10%)

总结

基于上述原因,建议始终使用 总位移 = currentX - initialX 绝对位移的方式计算