多个面板

config.ts
file.tsx
file.tsx
file.tsx
file.tsx
file.tsx

前言

拖拽功能由拖拽条、面板组成,如果为每个拖拽条单独添加鼠标事件,每个面板单独修改宽度,会增加很多行代码和工作量。因此考虑封装的方式较少代码量,首先是拖拽条的封装

拖拽条

1class DragElement {
2  static paramEleHistory = new Set();
3
4  constructor(dragEle, customDragMove) {
5    this.dragEle = dragEle;
6    this.isEnabled = true;
7    this.customDragMove = customDragMove;
8    this.dragEleBeginPos = undefined;
9    if (DragElement.paramEleHistory.has(this.dragEle)) {
10      return [...DragElement.paramEleHistory].find(item => item === this.dragEle);
11    }
12    DragElement.paramEleHistory.add(this.dragEle);
13
14    this.isBeginMove = false;
15    this.mouseBeginPos = undefined;
16    this.draggable();
17  }
18  // 鼠标位置初始值
19  onMoveDown(x, y) {
20    // todo 等待外部传入
21  }
22  onMouseMove(offSetX, offsetX, x, y) {
23    // todo 等待外部传入
24  }
25  // 鼠标位置结束
26  onMouseUp(x, y) {
27    // todo 等待外部传入
28
29  }
30  onMouseLeave(x, y) {
31    // todo 等待外部传入
32
33  }
34  
35  // 一系列工具函数
36
37
38  draggable = () => {
39    this.dragEle.addEventListener('touchstart', (event) => {
40      const touch = event.touches[0];
41      this.onMouseDownHandler(touch.clientX, touch.clientY);
42    });
43    this.dragEle.addEventListener('mousedown', (event) => {
44      this.onMouseDownHandler(event.x, event.y);
45    });
46
47    document.addEventListener('mousemove', (event) => {
48      this.dragEle.classList.add("ew-resize");
49      event.preventDefault();
50      if (this.isBeginMove) {
51        this.setDragElePos(event.x, event.y);
52      }
53    });
54    document.addEventListener('touchmove', (event) => {
55      event.preventDefault();
56      const touch = event.touches[0];
57      if (this.isBeginMove) {
58        this.setDragElePos(touch.clientX, touch.clientY);
59      }
60    }, { passive: false });
61
62    document.addEventListener('mouseup', (event) => {
63      this.isBeginMove = false;
64      document.body.classList.remove("ew-resize");
65
66      this.onMouseUp && this.onMouseUp(event.x, event.y);
67
68    });
69    
70     this.dragEle.addEventListener('mouseleave', (event) => {
71       this.onMouseLeave();
72
73    });
74    this.dragEle.addEventListener('touchend', (event) => {
75      this.isBeginMove = false;
76      const touch = event.touches[0];
77      document.body.classList.remove("ew-resize");
78      this.onMouseUp && this.onMouseUp(touch.clientX, touch.clientY);
79    });
80
81  }
82}

面板

1class PanelResize {
2  constructor(parentEle) {
3    // 一系列状态
4    this.init()
5  }
6init() {
7// 获取面板及拖拽元素
8const children = Array.from(this.parentEle.children);
9    this.totalWidth = this.getTotalWidth();
10
11    children.forEach(child => {
12      if (child.id.includes('panel')) {
13        this.panelsEle.push(child);
14      } else if (child.id.includes('handle')) {
15        this.handlesEle.push(child);
16      }
17    });
18}
19}

具体使用

1<body>
2  <div class="wrapper" id="wrapper-resize">
3    <div class="panel-one">panel-one</div>
4    <div class="handle-one"></div>
5    <div class="panel-two">panel-two</div>
6    <div class="handle-two"></div>
7    <div class="panel-three">panel-three</div>
8  </div>
9  <script>
10   // 传入父元素
11    const panelResize = new PanelResize(document.getElementById('wrapper-resize'), [[10,30], [20,30], [20,40]], 'vertical');
12  
13  </script>

重点问题:实现级联面板

级联面板是在拖拽时,首先对拖拽条左右面板进行伸缩,如果不够了,计算剩余量,将剩余量应用到下一个面板。以次类推,直到所有面板应用完毕,或者剩余量为0。但这种思路有一个问题是,如果面板直接应用偏移量,那剩余面板可能不能符合最大/最小限制,这样就不能保证每个面板都要在限制的范围内进行拖拽。所以就需要先知道总体偏移量,再结合限制范围进行偏移

1// 计算左右偏移量
2    const posMoveNumber = this.isLeftMove(offset);
3    const negMoveNumber = this.isRightMove(offset);
4    // 不能再偏移,直接返回
5    if (posMoveNumber <= Math.abs(offset) || negMoveNumber <= Math.abs(offset)) {
6      return;
7    }
8    // 比较左右和鼠标偏移量并进行偏移
9    const minMoveNumber = offset > 0
10      ? Math.min(offset, posMoveNumber, negMoveNumber)
11      : Math.max(offset, -posMoveNumber, -negMoveNumber);
12    moveLeftPanel(minMoveNumber);
13    moveRightPanel(minMoveNumber);

总结

级联面板是实现多面板的难点,可以通过预先计算偏移量实现。还有一些小细节要注意,比如因为是动态布局,一个面板的宽度变化会影响其他面板,所以需要预先保存各个面板的原始值,在计算好各自的偏移量后,一起修改。