单个面板

一、核心实现原理

通过监听主控元素的移动事件(鼠标拖拽或触摸移动),实时计算位移量,然后将这个位移量按比例映射到目标元素的宽高属性上,形成联动效果。

二、关键技术实现

1<div id="panel">panel</div>
2<div id="handler">handler ele</div>
1// 主控元素事件监听
2const handleEle = document.getElementById('handler');
3    const panelEle = document.getElementById('panel');
4    let isDragging = false;
5    let offsetX, offsetY;
6
7    let mouseBegin = {
8      x: undefined,
9      y: undefined
10    }
11    let eleBegin = {
12      x: undefined,
13      y: undefined
14    }
15    let panelSize = {
16      width: undefined,
17      height: undefined
18    }
19    let panelMinSize = {
20      width: 100,
21      height: 100
22    }
23
24
25    handleEle.addEventListener('mousedown', (e) => {
26      isDragging = true;
27      const rect = handleEle.getBoundingClientRect();
28      mouseBegin.x = e.x;
29      mouseBegin.y = e.y;
30      const style = window.getComputedStyle(handleEle);
31      const matrix = new DOMMatrix(style.transform);
32      eleBegin = { x: matrix.m41, y: matrix.m42 };
33
34      const panelElePos = panelEle.getBoundingClientRect();
35      const { width, height } = panelElePos;
36      panelSize = { width, height }
37
38    });
39
40    document.addEventListener('mousemove', (e) => {
41      if (!isDragging) return;
42      offsetX = e.x - mouseBegin.x;
43      offsetY = e.y - mouseBegin.y;
44      handleEle.style.transform = `translate(${eleBegin.x + offsetX}px, ${eleBegin.y + offsetY}px)`;
45
46      console.log(offsetX, panelSize.width + offsetX);
47      panelEle.style.width = Math.max(panelMinSize.width, panelSize.width + offsetX)+ 'px';
48      panelEle.style.height = Math.max(panelMinSize.height, panelSize.height + offsetY )+ 'px';
49    });
50
51    document.addEventListener('mouseup', () => {
52      isDragging = false;
53    });

三、最大最小宽高

1<div id="panel">panel</div>
2<div id="handler">handler ele</div>
1<script>
2
3    const handleEle = document.getElementById('handler');
4    const panelEle = document.getElementById('panel');
5    let isDragging = false;
6    let offsetX, offsetY;
7
8    let mouseBegin = {
9      x: undefined,
10      y: undefined
11    }
12    let eleBegin = {
13      x: undefined,
14      y: undefined
15    }
16    let panelSize = {
17      width: undefined,
18      height: undefined
19    }
20    let panelMinSize = {
21      width: 100,
22      height: 200
23    }
24
25    handleEle.addEventListener('mousedown', (e) => {
26      isDragging = true;
27      const rect = handleEle.getBoundingClientRect();
28      mouseBegin.x = e.x;
29      mouseBegin.y = e.y;
30      const style = window.getComputedStyle(handleEle);
31      const matrix = new DOMMatrix(style.transform);
32      eleBegin = { x: matrix.m41, y: matrix.m42 };
33
34      const panelElePos = panelEle.getBoundingClientRect();
35      const { width, height } = panelElePos;
36      panelSize = { width, height }
37
38    });
39
40    document.addEventListener('mousemove', (e) => {
41      if (!isDragging) return;
42      offsetX = e.x - mouseBegin.x;
43      offsetY = e.y - mouseBegin.y;
44
45      // 需要实时更新拖拽条的位置,这样在满足条件后,可以给拖拽条的偏移量设置固定值
46      const style = window.getComputedStyle(handleEle);
47      const matrix = new DOMMatrix(style.transform);
48      eleBegin = { x: matrix.m41, y: matrix.m42 };
49
50      let translateX;
51      let translateY;
52
53      if (panelSize.width + offsetX <= panelMinSize.width && offsetX < 0) {
54        translateX = eleBegin.x
55      } else if (panelSize.height + offsetY <= panelMinSize.height && offsetY < 0) {
56       translateY = eleBegin.y;
57      } else {
58        translateX = eleBegin.x + offsetX;
59        translateY = eleBegin.y + offsetY;
60      }
61    
62      handleEle.style.transform = `translate(${translateX}px, ${translateY}px)`;
63
64      mouseBegin = {x: e.x, y: e.y };
65
66      // 元素的最大最小宽度限制
67      const w = Math.max(panelSize.width + offsetX, panelMinSize.width);
68      const h = Math.max(panelSize.height + offsetY, panelMinSize.height);
69      panelEle.style.width = w + 'px';
70      panelEle.style.height = h+ 'px';
71      panelSize = { width: w, height: h}
72    });
73
74    document.addEventListener('mouseup', () => {
75      isDragging = false;
76    });
77
78  </script>

总结

在实现到达最大最小值拖拽条不能移动的需求时,不能只记录mousedown时拖拽条的位置,要记录实时位置,这样在到达限制后,可以给translateX或者translateY设置为固定值。