react-resize-demo 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -0
- package/README.md +257 -0
- package/dist/components/ResizeHandle/index.d.ts +8 -0
- package/dist/components/ResizeHandle/index.d.ts.map +1 -0
- package/dist/components/ResizePanel/index.d.ts +19 -0
- package/dist/components/ResizePanel/index.d.ts.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +724 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +727 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/package.json +61 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,727 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 虚拟节点管理模块
|
|
8
|
+
* 负责创建、更新、销毁虚拟节点,用于虚拟化拖拽
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
class VirtualNodeManager {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.virtualNodes = new Map(); // 存储虚拟节点映射:realEl -> virtualEl
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 创建虚拟节点
|
|
18
|
+
* @param {HTMLElement} originalEl - 原始节点
|
|
19
|
+
* @param {Object} config - 虚拟化配置
|
|
20
|
+
* @param {Object} config.style - 虚拟节点样式
|
|
21
|
+
* @param {string} config.className - 虚拟节点类名
|
|
22
|
+
* @returns {HTMLElement} 虚拟节点
|
|
23
|
+
*/
|
|
24
|
+
createVirtualNode(originalEl, config = {}) {
|
|
25
|
+
if (!originalEl || !originalEl.parentElement) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 如果已存在虚拟节点,先移除
|
|
30
|
+
if (this.virtualNodes.has(originalEl)) {
|
|
31
|
+
this.removeVirtualNode(originalEl);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 获取原始节点的位置和尺寸信息
|
|
35
|
+
const rect = originalEl.getBoundingClientRect();
|
|
36
|
+
const parentRect = originalEl.parentElement.getBoundingClientRect();
|
|
37
|
+
const computedStyle = window.getComputedStyle(originalEl);
|
|
38
|
+
|
|
39
|
+
// 创建虚拟节点(只复制结构,不复制内容以提高性能)
|
|
40
|
+
const virtualEl = originalEl.cloneNode(false); // false 表示不复制子节点
|
|
41
|
+
|
|
42
|
+
// 计算相对于父容器的位置
|
|
43
|
+
const top = rect.top - parentRect.top + (originalEl.parentElement.scrollTop || 0);
|
|
44
|
+
const left = rect.left - parentRect.left + (originalEl.parentElement.scrollLeft || 0);
|
|
45
|
+
|
|
46
|
+
// 设置虚拟节点样式
|
|
47
|
+
virtualEl.style.cssText = `
|
|
48
|
+
position: absolute;
|
|
49
|
+
top: ${top}px;
|
|
50
|
+
left: ${left}px;
|
|
51
|
+
width: ${rect.width}px;
|
|
52
|
+
height: ${rect.height}px;
|
|
53
|
+
margin: 0;
|
|
54
|
+
padding: ${computedStyle.padding};
|
|
55
|
+
border: ${computedStyle.border};
|
|
56
|
+
box-sizing: ${computedStyle.boxSizing};
|
|
57
|
+
pointer-events: none;
|
|
58
|
+
z-index: 10000;
|
|
59
|
+
opacity: 0.6;
|
|
60
|
+
background-color: ${computedStyle.backgroundColor || 'rgba(0, 123, 255, 0.1)'};
|
|
61
|
+
overflow: hidden;
|
|
62
|
+
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.3);
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
// 应用自定义样式
|
|
66
|
+
if (config.style) {
|
|
67
|
+
Object.assign(virtualEl.style, config.style);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 应用自定义类名
|
|
71
|
+
if (config.className) {
|
|
72
|
+
virtualEl.className = config.className;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 隐藏原始节点的内容(可选,通过设置透明度)
|
|
76
|
+
const originalOpacity = originalEl.style.opacity;
|
|
77
|
+
originalEl.style.opacity = '0.3';
|
|
78
|
+
originalEl.dataset.originalOpacity = originalOpacity || '';
|
|
79
|
+
|
|
80
|
+
// 将虚拟节点插入到父容器中
|
|
81
|
+
originalEl.parentElement.appendChild(virtualEl);
|
|
82
|
+
|
|
83
|
+
// 存储映射关系
|
|
84
|
+
this.virtualNodes.set(originalEl, virtualEl);
|
|
85
|
+
|
|
86
|
+
return virtualEl;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 更新虚拟节点尺寸
|
|
91
|
+
* @param {HTMLElement} originalEl - 原始节点
|
|
92
|
+
* @param {number} size - 新尺寸
|
|
93
|
+
* @param {string} direction - 方向 'horizontal' | 'vertical'
|
|
94
|
+
*/
|
|
95
|
+
updateVirtualNode(originalEl, size, direction) {
|
|
96
|
+
const virtualEl = this.virtualNodes.get(originalEl);
|
|
97
|
+
if (!virtualEl) return;
|
|
98
|
+
|
|
99
|
+
const sizeProperty = direction === 'horizontal' ? 'width' : 'height';
|
|
100
|
+
virtualEl.style[sizeProperty] = `${size}px`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 更新虚拟节点位置(用于级联调整)
|
|
105
|
+
* @param {HTMLElement} originalEl - 原始节点
|
|
106
|
+
* @param {number} newPosition - 新位置(绝对位置,不是偏移量)
|
|
107
|
+
* @param {string} direction - 方向 'horizontal' | 'vertical'
|
|
108
|
+
*/
|
|
109
|
+
updateVirtualNodePosition(originalEl, newPosition, direction) {
|
|
110
|
+
const virtualEl = this.virtualNodes.get(originalEl);
|
|
111
|
+
if (!virtualEl) return;
|
|
112
|
+
|
|
113
|
+
const positionProperty = direction === 'horizontal' ? 'left' : 'top';
|
|
114
|
+
virtualEl.style[positionProperty] = `${newPosition}px`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 移除虚拟节点
|
|
119
|
+
* @param {HTMLElement} originalEl - 原始节点
|
|
120
|
+
*/
|
|
121
|
+
removeVirtualNode(originalEl) {
|
|
122
|
+
const virtualEl = this.virtualNodes.get(originalEl);
|
|
123
|
+
if (!virtualEl) return;
|
|
124
|
+
|
|
125
|
+
// 恢复原始节点透明度
|
|
126
|
+
if (originalEl.dataset.originalOpacity !== undefined) {
|
|
127
|
+
originalEl.style.opacity = originalEl.dataset.originalOpacity;
|
|
128
|
+
delete originalEl.dataset.originalOpacity;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 移除虚拟节点
|
|
132
|
+
if (virtualEl.parentElement) {
|
|
133
|
+
virtualEl.parentElement.removeChild(virtualEl);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 移除映射关系
|
|
137
|
+
this.virtualNodes.delete(originalEl);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* 将最终尺寸应用到真实节点
|
|
142
|
+
* @param {HTMLElement} originalEl - 原始节点
|
|
143
|
+
* @param {number} finalSize - 最终尺寸
|
|
144
|
+
* @param {string} direction - 方向 'horizontal' | 'vertical'
|
|
145
|
+
*/
|
|
146
|
+
applyToRealNode(originalEl, finalSize, direction) {
|
|
147
|
+
const sizeProperty = direction === 'horizontal' ? 'width' : 'height';
|
|
148
|
+
originalEl.style[sizeProperty] = `${finalSize}px`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 移除所有虚拟节点
|
|
153
|
+
*/
|
|
154
|
+
removeAllVirtualNodes() {
|
|
155
|
+
const nodesToRemove = Array.from(this.virtualNodes.keys());
|
|
156
|
+
nodesToRemove.forEach(originalEl => {
|
|
157
|
+
this.removeVirtualNode(originalEl);
|
|
158
|
+
});
|
|
159
|
+
this.virtualNodes.clear();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 检查是否存在虚拟节点
|
|
164
|
+
* @param {HTMLElement} originalEl - 原始节点
|
|
165
|
+
* @returns {boolean}
|
|
166
|
+
*/
|
|
167
|
+
hasVirtualNode(originalEl) {
|
|
168
|
+
return this.virtualNodes.has(originalEl);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* 获取虚拟节点
|
|
173
|
+
* @param {HTMLElement} originalEl - 原始节点
|
|
174
|
+
* @returns {HTMLElement|null}
|
|
175
|
+
*/
|
|
176
|
+
getVirtualNode(originalEl) {
|
|
177
|
+
return this.virtualNodes.get(originalEl) || null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* 销毁管理器,清理所有资源
|
|
182
|
+
*/
|
|
183
|
+
destroy() {
|
|
184
|
+
this.removeAllVirtualNodes();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// @ts-expect-error - VirtualNodeManager is a JS file
|
|
189
|
+
|
|
190
|
+
class ResizeAbleCore {
|
|
191
|
+
constructor(options) {
|
|
192
|
+
this.prePanelEl = options.prePanelEl;
|
|
193
|
+
this.nextPanelEl = options.nextPanelEl;
|
|
194
|
+
this.getPanelInfo = options.getPanelInfo;
|
|
195
|
+
this.prePanelIndex = options.prePanelIndex;
|
|
196
|
+
this.nextPanelIndex = options.nextPanelIndex;
|
|
197
|
+
this.direction = options.direction;
|
|
198
|
+
this.virtualEnabled = options.virtualEnabled || false;
|
|
199
|
+
this.virtualConfig = options.virtualConfig || {};
|
|
200
|
+
|
|
201
|
+
this.isResizing = false;
|
|
202
|
+
this.startPos = 0;
|
|
203
|
+
this.prePanelStartSize = 0;
|
|
204
|
+
this.nextPanelStartSize = 0;
|
|
205
|
+
this.allPanelsStartSizes = new Map();
|
|
206
|
+
this.allPanelsStartPositions = new Map(); // 记录面板初始位置(虚拟化模式使用)
|
|
207
|
+
this.handleSize = options.handleSize || 0; // 拖拽器尺寸(宽度或高度,根据方向)
|
|
208
|
+
|
|
209
|
+
// 如果启用虚拟化,创建虚拟节点管理器
|
|
210
|
+
if (this.virtualEnabled) {
|
|
211
|
+
this.virtualNodeManager = new VirtualNodeManager();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
startResize() {
|
|
215
|
+
console.log(11111);
|
|
216
|
+
// 设置开始拖拽
|
|
217
|
+
this.isResizing = true;
|
|
218
|
+
|
|
219
|
+
// 记录前一个面板的开始大小
|
|
220
|
+
this.prePanelStartSize = this.getSize(this.prePanelEl);
|
|
221
|
+
this.allPanelsStartSizes.set(this.prePanelIndex, this.prePanelStartSize);
|
|
222
|
+
// 记录后一个面板的开始大小
|
|
223
|
+
this.nextPanelStartSize = this.getSize(this.nextPanelEl);
|
|
224
|
+
this.allPanelsStartSizes.set(this.nextPanelIndex, this.nextPanelStartSize);
|
|
225
|
+
|
|
226
|
+
// 根据方向设置尺寸属性
|
|
227
|
+
const sizeProperty = this.direction === 'horizontal' ? 'width' : 'height';
|
|
228
|
+
|
|
229
|
+
if (this.virtualEnabled && this.virtualNodeManager) {
|
|
230
|
+
// 虚拟化模式:创建虚拟节点并记录初始位置
|
|
231
|
+
const prePos = this.getPosition(this.prePanelEl);
|
|
232
|
+
this.allPanelsStartPositions.set(this.prePanelIndex, prePos);
|
|
233
|
+
this.virtualNodeManager.createVirtualNode(this.prePanelEl, this.virtualConfig);
|
|
234
|
+
|
|
235
|
+
const nextPos = this.getPosition(this.nextPanelEl);
|
|
236
|
+
this.allPanelsStartPositions.set(this.nextPanelIndex, nextPos);
|
|
237
|
+
this.virtualNodeManager.createVirtualNode(this.nextPanelEl, this.virtualConfig);
|
|
238
|
+
|
|
239
|
+
// 记录前面面板的初始尺寸和位置并创建虚拟节点
|
|
240
|
+
let prevIndex = this.prePanelIndex - 1;
|
|
241
|
+
while (prevIndex >= 0) {
|
|
242
|
+
const panelInfo = this.getPanelInfo(prevIndex);
|
|
243
|
+
if (!panelInfo) break;
|
|
244
|
+
|
|
245
|
+
const size = this.getSize(panelInfo.panelEl);
|
|
246
|
+
const pos = this.getPosition(panelInfo.panelEl);
|
|
247
|
+
this.allPanelsStartSizes.set(prevIndex, size);
|
|
248
|
+
this.allPanelsStartPositions.set(prevIndex, pos);
|
|
249
|
+
this.virtualNodeManager.createVirtualNode(panelInfo.panelEl, this.virtualConfig);
|
|
250
|
+
prevIndex--;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// 记录后续面板的初始尺寸和位置并创建虚拟节点
|
|
254
|
+
let nextIndex = this.nextPanelIndex + 1;
|
|
255
|
+
let nextPanelInfo = this.getPanelInfo(nextIndex);
|
|
256
|
+
while (nextPanelInfo) {
|
|
257
|
+
const size = this.getSize(nextPanelInfo.panelEl);
|
|
258
|
+
const pos = this.getPosition(nextPanelInfo.panelEl);
|
|
259
|
+
this.allPanelsStartSizes.set(nextIndex, size);
|
|
260
|
+
this.allPanelsStartPositions.set(nextIndex, pos);
|
|
261
|
+
this.virtualNodeManager.createVirtualNode(nextPanelInfo.panelEl, this.virtualConfig);
|
|
262
|
+
nextIndex++;
|
|
263
|
+
nextPanelInfo = this.getPanelInfo(nextIndex);
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
// 非虚拟化模式:直接操作真实节点
|
|
267
|
+
// 禁用flex
|
|
268
|
+
this.prePanelEl.style.flex = 'none';
|
|
269
|
+
this.prePanelEl.style[sizeProperty] = `${this.prePanelStartSize}px`;
|
|
270
|
+
this.nextPanelEl.style.flex = 'none';
|
|
271
|
+
this.nextPanelEl.style[sizeProperty] = `${this.nextPanelStartSize}px`;
|
|
272
|
+
|
|
273
|
+
// 记录前面面板的初始尺寸(用于向前拖拽时的级联调整)
|
|
274
|
+
let prevIndex = this.prePanelIndex - 1;
|
|
275
|
+
while (prevIndex >= 0) {
|
|
276
|
+
const panelInfo = this.getPanelInfo(prevIndex);
|
|
277
|
+
if (!panelInfo) break;
|
|
278
|
+
|
|
279
|
+
const size = this.getSize(panelInfo.panelEl);
|
|
280
|
+
this.allPanelsStartSizes.set(prevIndex, size);
|
|
281
|
+
panelInfo.panelEl.style.flex = 'none';
|
|
282
|
+
panelInfo.panelEl.style[sizeProperty] = `${size}px`;
|
|
283
|
+
prevIndex--;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// 记录后续面板的初始尺寸(用于向后拖拽时的级联调整)
|
|
287
|
+
let nextIndex = this.nextPanelIndex + 1;
|
|
288
|
+
let nextPanelInfo = this.getPanelInfo(nextIndex);
|
|
289
|
+
while (nextPanelInfo) {
|
|
290
|
+
const size = this.getSize(nextPanelInfo.panelEl);
|
|
291
|
+
this.allPanelsStartSizes.set(nextIndex, size);
|
|
292
|
+
nextPanelInfo.panelEl.style.flex = 'none';
|
|
293
|
+
nextPanelInfo.panelEl.style[sizeProperty] = `${size}px`;
|
|
294
|
+
nextIndex++;
|
|
295
|
+
nextPanelInfo = this.getPanelInfo(nextIndex);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
onResize(delta) {
|
|
300
|
+
if (!this.isResizing) return;
|
|
301
|
+
|
|
302
|
+
if (delta > 0) {
|
|
303
|
+
// 向后拖拽(水平布局向右,垂直布局向下):扩大前一个面板,缩小后一个面板
|
|
304
|
+
this.adjustPanelsNext(delta);
|
|
305
|
+
} else {
|
|
306
|
+
// 向前拖拽(水平布局向左,垂直布局向上):缩小前一个面板,扩大后一个面板
|
|
307
|
+
// 将负数转为正数处理
|
|
308
|
+
this.adjustPanelsPre(-delta);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
adjustPanelsNext(delta) {
|
|
312
|
+
console.log('next', 'kkkkkkk');
|
|
313
|
+
let remainingDelta = delta;
|
|
314
|
+
const sizeProperty = this.direction === 'horizontal' ? 'width' : 'height';
|
|
315
|
+
|
|
316
|
+
// 尝试从后一个面板获取空间
|
|
317
|
+
const nextPanelInfo = this.getPanelInfo(this.nextPanelIndex);
|
|
318
|
+
if (nextPanelInfo) {
|
|
319
|
+
const nextStartSize = this.allPanelsStartSizes.get(this.nextPanelIndex);
|
|
320
|
+
const targetNextSize = nextStartSize - remainingDelta;
|
|
321
|
+
const newNextSize = Math.max(nextPanelInfo.minSize, targetNextSize);
|
|
322
|
+
const actualReduction = nextStartSize - newNextSize;
|
|
323
|
+
|
|
324
|
+
// 虚拟化模式下更新虚拟节点,否则更新真实节点
|
|
325
|
+
if (this.virtualEnabled && this.virtualNodeManager) {
|
|
326
|
+
this.virtualNodeManager.updateVirtualNode(this.nextPanelEl, newNextSize, this.direction);
|
|
327
|
+
} else {
|
|
328
|
+
this.nextPanelEl.style[sizeProperty] = `${newNextSize}px`;
|
|
329
|
+
}
|
|
330
|
+
remainingDelta -= actualReduction;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
console.log(remainingDelta, 'kkkkkk');
|
|
334
|
+
|
|
335
|
+
// 如果后一个面板达到了最小值,继续从后续的面板中获取空间
|
|
336
|
+
if (remainingDelta > 0) {
|
|
337
|
+
let nextIndex = this.nextPanelIndex + 1;
|
|
338
|
+
while (remainingDelta > 0) {
|
|
339
|
+
const nextPanelInfo = this.getPanelInfo(nextIndex);
|
|
340
|
+
if (!nextPanelInfo) break;
|
|
341
|
+
const nextStartSize = this.allPanelsStartSizes.get(nextIndex);
|
|
342
|
+
const targetNextSize = nextStartSize - remainingDelta;
|
|
343
|
+
const newNextSize = Math.max(nextPanelInfo.minSize, targetNextSize);
|
|
344
|
+
const actualReduction = nextStartSize - newNextSize;
|
|
345
|
+
|
|
346
|
+
// 虚拟化模式下更新虚拟节点,否则更新真实节点
|
|
347
|
+
if (this.virtualEnabled && this.virtualNodeManager) {
|
|
348
|
+
this.virtualNodeManager.updateVirtualNode(nextPanelInfo.panelEl, newNextSize, this.direction);
|
|
349
|
+
} else {
|
|
350
|
+
nextPanelInfo.panelEl.style[sizeProperty] = `${newNextSize}px`;
|
|
351
|
+
}
|
|
352
|
+
remainingDelta -= actualReduction;
|
|
353
|
+
if (newNextSize <= nextPanelInfo.minSize && remainingDelta > 0) {
|
|
354
|
+
nextIndex++;
|
|
355
|
+
} else {
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// 扩大前一个面板
|
|
362
|
+
const prePanelInfo = this.getPanelInfo(this.prePanelIndex);
|
|
363
|
+
if (prePanelInfo) {
|
|
364
|
+
const preStartSize = this.allPanelsStartSizes.get(this.prePanelIndex);
|
|
365
|
+
const actualGained = delta - remainingDelta; // 实际获得的尺寸
|
|
366
|
+
const newPreSize = preStartSize + actualGained;
|
|
367
|
+
|
|
368
|
+
// 虚拟化模式下更新虚拟节点,否则更新真实节点
|
|
369
|
+
if (this.virtualEnabled && this.virtualNodeManager) {
|
|
370
|
+
this.virtualNodeManager.updateVirtualNode(this.prePanelEl, newPreSize, this.direction);
|
|
371
|
+
|
|
372
|
+
// 重新计算所有面板的位置(基于尺寸变化)
|
|
373
|
+
this.recalculateAllPanelsPositions();
|
|
374
|
+
} else {
|
|
375
|
+
this.prePanelEl.style[sizeProperty] = `${newPreSize}px`;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
adjustPanelsPre(delta) {
|
|
380
|
+
// 向前拖拽(水平布局向左,垂直布局向上):缩小前一个面板,扩大后一个面板
|
|
381
|
+
// delta 此时是正数(表示向前拖拽的距离)
|
|
382
|
+
let remainingDelta = delta;
|
|
383
|
+
let totalReduced = 0; // 记录从前一个面板实际减少的尺寸总和
|
|
384
|
+
const sizeProperty = this.direction === 'horizontal' ? 'width' : 'height';
|
|
385
|
+
|
|
386
|
+
// 先尝试缩小前一个面板
|
|
387
|
+
const prePanelInfo = this.getPanelInfo(this.prePanelIndex);
|
|
388
|
+
if (prePanelInfo) {
|
|
389
|
+
const preStartSize = this.allPanelsStartSizes.get(this.prePanelIndex);
|
|
390
|
+
const targetPreSize = preStartSize - remainingDelta;
|
|
391
|
+
const newPreSize = Math.max(prePanelInfo.minSize, targetPreSize);
|
|
392
|
+
const actualReduction = preStartSize - newPreSize;
|
|
393
|
+
|
|
394
|
+
// 虚拟化模式下更新虚拟节点,否则更新真实节点
|
|
395
|
+
if (this.virtualEnabled && this.virtualNodeManager) {
|
|
396
|
+
this.virtualNodeManager.updateVirtualNode(this.prePanelEl, newPreSize, this.direction);
|
|
397
|
+
} else {
|
|
398
|
+
this.prePanelEl.style[sizeProperty] = `${newPreSize}px`;
|
|
399
|
+
}
|
|
400
|
+
totalReduced += actualReduction;
|
|
401
|
+
remainingDelta -= actualReduction;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// 如果前一个面板达到最小值,继续缩小更前面的面板(prevPanel)
|
|
405
|
+
// 这样可以实现"依次后延"的效果
|
|
406
|
+
if (remainingDelta > 0) {
|
|
407
|
+
let prevIndex = this.prePanelIndex - 1;
|
|
408
|
+
console.log(prevIndex, this.prePanelIndex, 'kkkkkkkk');
|
|
409
|
+
while (remainingDelta > 0 && prevIndex >= 0) {
|
|
410
|
+
const prevPanelInfo = this.getPanelInfo(prevIndex);
|
|
411
|
+
if (!prevPanelInfo) break;
|
|
412
|
+
|
|
413
|
+
const prevStartSize = this.allPanelsStartSizes.get(prevIndex);
|
|
414
|
+
if (prevStartSize === undefined) break;
|
|
415
|
+
|
|
416
|
+
const targetPrevSize = prevStartSize - remainingDelta;
|
|
417
|
+
const newPrevSize = Math.max(prevPanelInfo.minSize, targetPrevSize);
|
|
418
|
+
const actualReduction = prevStartSize - newPrevSize;
|
|
419
|
+
|
|
420
|
+
// 虚拟化模式下更新虚拟节点,否则更新真实节点
|
|
421
|
+
if (this.virtualEnabled && this.virtualNodeManager) {
|
|
422
|
+
this.virtualNodeManager.updateVirtualNode(prevPanelInfo.panelEl, newPrevSize, this.direction);
|
|
423
|
+
} else {
|
|
424
|
+
prevPanelInfo.panelEl.style[sizeProperty] = `${newPrevSize}px`;
|
|
425
|
+
}
|
|
426
|
+
totalReduced += actualReduction; // 将这部分空间也加到后一个面板
|
|
427
|
+
remainingDelta -= actualReduction;
|
|
428
|
+
|
|
429
|
+
if (newPrevSize <= prevPanelInfo.minSize && remainingDelta > 0) {
|
|
430
|
+
prevIndex--; // 继续向前查找
|
|
431
|
+
} else {
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// 扩大后一个面板(使用实际减少的尺寸)
|
|
438
|
+
const nextPanelInfo = this.getPanelInfo(this.nextPanelIndex);
|
|
439
|
+
if (nextPanelInfo) {
|
|
440
|
+
const nextStartSize = this.allPanelsStartSizes.get(this.nextPanelIndex);
|
|
441
|
+
const newNextSize = nextStartSize + totalReduced;
|
|
442
|
+
|
|
443
|
+
// 虚拟化模式下更新虚拟节点,否则更新真实节点
|
|
444
|
+
if (this.virtualEnabled && this.virtualNodeManager) {
|
|
445
|
+
this.virtualNodeManager.updateVirtualNode(this.nextPanelEl, newNextSize, this.direction);
|
|
446
|
+
|
|
447
|
+
// 重新计算所有面板的位置(基于尺寸变化)
|
|
448
|
+
this.recalculateAllPanelsPositions();
|
|
449
|
+
} else {
|
|
450
|
+
this.nextPanelEl.style[sizeProperty] = `${newNextSize}px`;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* 重新计算所有面板的位置(虚拟化模式使用)
|
|
456
|
+
* 基于每个面板的初始位置和前面所有面板的尺寸变化
|
|
457
|
+
*/
|
|
458
|
+
recalculateAllPanelsPositions() {
|
|
459
|
+
if (!this.virtualEnabled || !this.virtualNodeManager) return;
|
|
460
|
+
|
|
461
|
+
// 从第一个面板开始,顺序计算每个面板的新位置
|
|
462
|
+
// 使用累积方式:从第一个面板的初始位置开始,依次加上每个面板的当前尺寸和拖拽器尺寸
|
|
463
|
+
const firstPanelStartPos = this.allPanelsStartPositions.get(0) || 0;
|
|
464
|
+
let currentPosition = firstPanelStartPos;
|
|
465
|
+
|
|
466
|
+
let index = 0;
|
|
467
|
+
let panelInfo = this.getPanelInfo(index);
|
|
468
|
+
while (panelInfo) {
|
|
469
|
+
const startPos = this.allPanelsStartPositions.get(index);
|
|
470
|
+
|
|
471
|
+
if (startPos !== undefined) {
|
|
472
|
+
// 获取虚拟节点
|
|
473
|
+
const virtualEl = this.virtualNodeManager.getVirtualNode(panelInfo.panelEl);
|
|
474
|
+
if (virtualEl) {
|
|
475
|
+
// 如果是第一个面板,使用初始位置
|
|
476
|
+
if (index === 0) {
|
|
477
|
+
currentPosition = startPos;
|
|
478
|
+
} else {
|
|
479
|
+
// 对于后续面板,使用累积方式计算位置
|
|
480
|
+
// 从第一个面板开始,累积所有前面面板的尺寸和拖拽器尺寸
|
|
481
|
+
currentPosition = firstPanelStartPos;
|
|
482
|
+
for (let i = 0; i < index; i++) {
|
|
483
|
+
const prevInfo = this.getPanelInfo(i);
|
|
484
|
+
if (prevInfo) {
|
|
485
|
+
const prevVEl = this.virtualNodeManager.getVirtualNode(prevInfo.panelEl);
|
|
486
|
+
if (prevVEl) {
|
|
487
|
+
const prevSize = this.direction === 'horizontal'
|
|
488
|
+
? prevVEl.offsetWidth
|
|
489
|
+
: prevVEl.offsetHeight;
|
|
490
|
+
currentPosition += prevSize + this.handleSize;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// 更新虚拟节点的位置
|
|
497
|
+
this.virtualNodeManager.updateVirtualNodePosition(panelInfo.panelEl, currentPosition, this.direction);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
index++;
|
|
502
|
+
panelInfo = this.getPanelInfo(index);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
getSize(el) {
|
|
506
|
+
return this.direction === 'horizontal' ? el.offsetWidth : el.offsetHeight;
|
|
507
|
+
}
|
|
508
|
+
getPosition(el) {
|
|
509
|
+
// 获取元素相对于父容器的位置
|
|
510
|
+
if (this.direction === 'horizontal') {
|
|
511
|
+
return el.offsetLeft;
|
|
512
|
+
} else {
|
|
513
|
+
return el.offsetTop;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
endResize() {
|
|
517
|
+
this.isResizing = false;
|
|
518
|
+
|
|
519
|
+
if (this.virtualEnabled && this.virtualNodeManager) {
|
|
520
|
+
// 虚拟化模式:将最终尺寸应用到真实节点
|
|
521
|
+
const sizeProperty = this.direction === 'horizontal' ? 'width' : 'height';
|
|
522
|
+
|
|
523
|
+
// 获取所有虚拟节点的最终尺寸并应用到真实节点
|
|
524
|
+
this.allPanelsStartSizes.forEach((startSize, index) => {
|
|
525
|
+
const panelInfo = this.getPanelInfo(index);
|
|
526
|
+
if (!panelInfo) return;
|
|
527
|
+
|
|
528
|
+
const virtualEl = this.virtualNodeManager.getVirtualNode(panelInfo.panelEl);
|
|
529
|
+
if (virtualEl) {
|
|
530
|
+
const finalSize = this.direction === 'horizontal'
|
|
531
|
+
? virtualEl.offsetWidth
|
|
532
|
+
: virtualEl.offsetHeight;
|
|
533
|
+
|
|
534
|
+
// 应用最终尺寸到真实节点
|
|
535
|
+
panelInfo.panelEl.style.flex = 'none';
|
|
536
|
+
panelInfo.panelEl.style[sizeProperty] = `${finalSize}px`;
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
// 清理所有虚拟节点
|
|
541
|
+
this.virtualNodeManager.removeAllVirtualNodes();
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
this.allPanelsStartSizes.clear();
|
|
545
|
+
}
|
|
546
|
+
destroy() {
|
|
547
|
+
this.endResize();
|
|
548
|
+
// 清理虚拟节点管理器
|
|
549
|
+
if (this.virtualNodeManager) {
|
|
550
|
+
this.virtualNodeManager.destroy();
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const ResizeableContext = React.createContext({
|
|
556
|
+
panelCount: 0,
|
|
557
|
+
registerPanel: () => 0,
|
|
558
|
+
unregisterPanel: () => { },
|
|
559
|
+
getPanelInfo: () => null,
|
|
560
|
+
getPanelIndex: () => -1,
|
|
561
|
+
direction: 'horizontal',
|
|
562
|
+
panelInfos: [],
|
|
563
|
+
virtualConfig: { enabled: false },
|
|
564
|
+
});
|
|
565
|
+
const ResizeablePanelGroup = ({ children, direction = 'horizontal', style, virtual = false, virtualConfig = {}, }) => {
|
|
566
|
+
const panelInfos = React.useRef([]);
|
|
567
|
+
const [panelCount, setPanelCount] = React.useState(0);
|
|
568
|
+
const registerPanel = React.useCallback((panelEl, minSize) => {
|
|
569
|
+
const index = panelInfos.current.length;
|
|
570
|
+
panelInfos.current.push({ panelEl, minSize });
|
|
571
|
+
setPanelCount(panelInfos.current.length);
|
|
572
|
+
console.log(panelInfos.current, 'panelInfos.current');
|
|
573
|
+
return index;
|
|
574
|
+
}, []);
|
|
575
|
+
const unregisterPanel = React.useCallback((panelEl) => {
|
|
576
|
+
panelInfos.current = panelInfos.current.filter(info => info.panelEl !== panelEl);
|
|
577
|
+
setPanelCount(panelInfos.current.length);
|
|
578
|
+
}, []);
|
|
579
|
+
const getPanelInfo = (index) => {
|
|
580
|
+
return panelInfos.current[index] || null;
|
|
581
|
+
};
|
|
582
|
+
const getPanelIndex = (panelEl) => {
|
|
583
|
+
return panelInfos.current.findIndex(info => info.panelEl === panelEl);
|
|
584
|
+
};
|
|
585
|
+
const childrenArray = React.Children.toArray(children);
|
|
586
|
+
const panelsWithHandles = [];
|
|
587
|
+
console.log(childrenArray, panelInfos.current, 'childrenArray');
|
|
588
|
+
childrenArray.forEach((child, index) => {
|
|
589
|
+
panelsWithHandles.push(child);
|
|
590
|
+
// 在面板之间插入拖拽器(最后一个面板后不插入)
|
|
591
|
+
if (index < childrenArray.length - 1) {
|
|
592
|
+
panelsWithHandles.push(jsxRuntime.jsx(ResizeHandle, { prePanelIndex: index, nextPanelIndex: index + 1, direction: direction }, `handle-${index}`));
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
// 合并虚拟化配置
|
|
596
|
+
const mergedVirtualConfig = {
|
|
597
|
+
enabled: virtual,
|
|
598
|
+
...virtualConfig,
|
|
599
|
+
};
|
|
600
|
+
return (jsxRuntime.jsx(ResizeableContext.Provider, { value: {
|
|
601
|
+
panelCount: panelCount,
|
|
602
|
+
registerPanel,
|
|
603
|
+
unregisterPanel,
|
|
604
|
+
getPanelInfo,
|
|
605
|
+
getPanelIndex,
|
|
606
|
+
direction,
|
|
607
|
+
panelInfos: panelInfos.current,
|
|
608
|
+
virtualConfig: mergedVirtualConfig,
|
|
609
|
+
}, children: jsxRuntime.jsx("div", { style: {
|
|
610
|
+
display: 'flex',
|
|
611
|
+
flexDirection: direction === 'horizontal' ? 'row' : 'column',
|
|
612
|
+
height: '100%',
|
|
613
|
+
position: 'relative', // 为虚拟节点定位提供参考
|
|
614
|
+
...style,
|
|
615
|
+
}, children: panelsWithHandles }) }));
|
|
616
|
+
};
|
|
617
|
+
const ResizeablePanel = ({ children, minSize = 100,
|
|
618
|
+
// onResize, // 暂时未使用,保留以备将来使用
|
|
619
|
+
}) => {
|
|
620
|
+
const panelRef = React.useRef(null);
|
|
621
|
+
const panelIndexRef = React.useRef(-1);
|
|
622
|
+
const { registerPanel, unregisterPanel, direction } = React.useContext(ResizeableContext);
|
|
623
|
+
React.useEffect(() => {
|
|
624
|
+
if (!panelRef.current)
|
|
625
|
+
return;
|
|
626
|
+
const panelEl = panelRef.current;
|
|
627
|
+
panelIndexRef.current = registerPanel(panelEl, minSize);
|
|
628
|
+
return () => {
|
|
629
|
+
unregisterPanel(panelEl);
|
|
630
|
+
};
|
|
631
|
+
}, [minSize, registerPanel, unregisterPanel]);
|
|
632
|
+
return (jsxRuntime.jsx("div", { ref: panelRef, style: {
|
|
633
|
+
flex: 1,
|
|
634
|
+
minWidth: direction === 'horizontal' ? minSize : undefined,
|
|
635
|
+
minHeight: direction === 'vertical' ? minSize : undefined,
|
|
636
|
+
width: 'auto',
|
|
637
|
+
overflow: 'hidden',
|
|
638
|
+
position: 'relative',
|
|
639
|
+
}, children: jsxRuntime.jsx("div", { style: { height: '100%', padding: 16 }, children: children }) }));
|
|
640
|
+
};
|
|
641
|
+
const ResizeHandle = ({ prePanelIndex, nextPanelIndex, direction, }) => {
|
|
642
|
+
const handleRef = React.useRef(null);
|
|
643
|
+
const coreInstanceRef = React.useRef(null);
|
|
644
|
+
const { getPanelInfo, panelCount, virtualConfig } = React.useContext(ResizeableContext);
|
|
645
|
+
React.useEffect(() => {
|
|
646
|
+
// 确保所需的面板索引都已注册
|
|
647
|
+
// 需要确保 nextPanelIndex 对应的面板已经注册(因为索引从0开始,所以需要 >= nextPanelIndex + 1)
|
|
648
|
+
if (panelCount <= nextPanelIndex || !handleRef.current) {
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
const prePanelInfo = getPanelInfo(prePanelIndex);
|
|
652
|
+
const nextPanelInfo = getPanelInfo(nextPanelIndex);
|
|
653
|
+
if (!prePanelInfo || !nextPanelInfo)
|
|
654
|
+
return;
|
|
655
|
+
// 获取拖拽器的尺寸
|
|
656
|
+
const handleSize = handleRef.current
|
|
657
|
+
? (direction === 'horizontal'
|
|
658
|
+
? handleRef.current.offsetWidth
|
|
659
|
+
: handleRef.current.offsetHeight)
|
|
660
|
+
: (direction === 'horizontal' ? 10 : 10); // 默认10px
|
|
661
|
+
coreInstanceRef.current = new ResizeAbleCore({
|
|
662
|
+
prePanelEl: prePanelInfo.panelEl,
|
|
663
|
+
nextPanelEl: nextPanelInfo.panelEl,
|
|
664
|
+
getPanelInfo,
|
|
665
|
+
prePanelIndex,
|
|
666
|
+
nextPanelIndex,
|
|
667
|
+
direction,
|
|
668
|
+
virtualEnabled: virtualConfig.enabled || false,
|
|
669
|
+
virtualConfig: {
|
|
670
|
+
style: virtualConfig.style,
|
|
671
|
+
className: virtualConfig.className,
|
|
672
|
+
},
|
|
673
|
+
handleSize, // 传递拖拽器尺寸
|
|
674
|
+
});
|
|
675
|
+
// 将拖拽器的开始/移动/结束事件绑定至核心类
|
|
676
|
+
const handleEl = handleRef.current;
|
|
677
|
+
let isResizing = false;
|
|
678
|
+
let startPos = 0;
|
|
679
|
+
const startResize = (e) => {
|
|
680
|
+
console.log(9999999);
|
|
681
|
+
e.preventDefault();
|
|
682
|
+
isResizing = true;
|
|
683
|
+
startPos = direction === 'horizontal' ? e.clientX : e.clientY;
|
|
684
|
+
if (coreInstanceRef.current) {
|
|
685
|
+
coreInstanceRef.current.startResize();
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
const onResizeMove = (e) => {
|
|
689
|
+
if (!isResizing || !coreInstanceRef.current)
|
|
690
|
+
return;
|
|
691
|
+
const currentPos = direction === 'horizontal' ? e.clientX : e.clientY;
|
|
692
|
+
const delta = currentPos - startPos;
|
|
693
|
+
coreInstanceRef.current.onResize(delta);
|
|
694
|
+
};
|
|
695
|
+
const endResize = () => {
|
|
696
|
+
if (isResizing && coreInstanceRef.current) {
|
|
697
|
+
isResizing = false;
|
|
698
|
+
coreInstanceRef.current.endResize();
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
handleEl.addEventListener('mousedown', startResize);
|
|
702
|
+
document.addEventListener('mousemove', onResizeMove);
|
|
703
|
+
document.addEventListener('mouseup', endResize);
|
|
704
|
+
return () => {
|
|
705
|
+
handleEl.removeEventListener('mousedown', startResize);
|
|
706
|
+
document.removeEventListener('mousemove', onResizeMove);
|
|
707
|
+
document.removeEventListener('mouseup', endResize);
|
|
708
|
+
if (coreInstanceRef.current) {
|
|
709
|
+
coreInstanceRef.current.destroy();
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
}, [prePanelIndex, nextPanelIndex, direction, getPanelInfo, panelCount, virtualConfig]);
|
|
713
|
+
const isHorizontal = direction === 'horizontal';
|
|
714
|
+
return (jsxRuntime.jsx("div", { ref: handleRef, style: {
|
|
715
|
+
position: 'relative',
|
|
716
|
+
width: isHorizontal ? '10px' : '100%',
|
|
717
|
+
height: isHorizontal ? '100%' : '10px',
|
|
718
|
+
backgroundColor: '#000',
|
|
719
|
+
cursor: isHorizontal ? 'ew-resize' : 'ns-resize',
|
|
720
|
+
zIndex: 1000,
|
|
721
|
+
flexShrink: 0,
|
|
722
|
+
} }));
|
|
723
|
+
};
|
|
724
|
+
|
|
725
|
+
exports.ResizeablePanel = ResizeablePanel;
|
|
726
|
+
exports.ResizeablePanelGroup = ResizeablePanelGroup;
|
|
727
|
+
//# sourceMappingURL=index.js.map
|