electron-drag-plus 1.0.0
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/LICENSE +21 -0
- package/README.md +378 -0
- package/dist/example.d.ts +1 -0
- package/dist/example.js +77 -0
- package/dist/index.d.ts +110 -0
- package/dist/index.js +187 -0
- package/dist/renderer.d.ts +58 -0
- package/dist/renderer.js +216 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 electron-drag-plus
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
# electron-drag-plus
|
|
2
|
+
|
|
3
|
+
增强版Electron窗口拖拽库,解决窗口抖动、不同分辨率/缩放导致的闪屏问题,并支持拖拽区域忽略鼠标事件。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- ✅ 解决Electron原生拖拽可能出现的窗口抖动问题
|
|
8
|
+
- ✅ 修复不同分辨率和显示器缩放导致的拖拽闪屏问题
|
|
9
|
+
- ✅ 智能识别并忽略拖拽区域内的交互元素(按钮、输入框等)
|
|
10
|
+
- ✅ 支持自定义忽略元素选择器
|
|
11
|
+
- ✅ 提供平滑拖拽体验
|
|
12
|
+
- ✅ 支持高DPI显示器
|
|
13
|
+
- ✅ 简单易用的API
|
|
14
|
+
- ✅ TypeScript支持
|
|
15
|
+
|
|
16
|
+
## 安装
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install electron-drag-plus
|
|
20
|
+
# 或
|
|
21
|
+
yarn add electron-drag-plus
|
|
22
|
+
# 或
|
|
23
|
+
pnpm add electron-drag-plus
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 使用方法
|
|
27
|
+
|
|
28
|
+
### 主进程使用
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
// 在主进程中
|
|
32
|
+
import { app, BrowserWindow } from 'electron';
|
|
33
|
+
import { DragPlus } from 'electron-drag-plus';
|
|
34
|
+
|
|
35
|
+
// 创建窗口时初始化拖拽增强
|
|
36
|
+
function createWindow() {
|
|
37
|
+
const win = new BrowserWindow({
|
|
38
|
+
width: 800,
|
|
39
|
+
height: 600,
|
|
40
|
+
frame: false, // 无边框窗口
|
|
41
|
+
webPreferences: {
|
|
42
|
+
nodeIntegration: true,
|
|
43
|
+
contextIsolation: false
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// 初始化拖拽增强
|
|
48
|
+
const dragPlus = new DragPlus(win, {
|
|
49
|
+
ignoreSelectors: ['.no-drag', '#close-button'],
|
|
50
|
+
enableHighDPI: true,
|
|
51
|
+
smoothDrag: true
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// 手动启用特定元素的拖拽
|
|
55
|
+
dragPlus.enableDrag('.title-bar');
|
|
56
|
+
|
|
57
|
+
// 手动禁用特定元素的拖拽
|
|
58
|
+
dragPlus.disableDrag('.window-controls');
|
|
59
|
+
|
|
60
|
+
win.loadFile('index.html');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
app.whenReady().then(createWindow);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 渲染进程使用
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
// 在渲染进程中
|
|
70
|
+
import { initDragPlus, setupDraggableArea, enableDrag, disableDrag } from 'electron-drag-plus/dist/renderer';
|
|
71
|
+
|
|
72
|
+
// 初始化拖拽功能
|
|
73
|
+
initDragPlus({
|
|
74
|
+
ignoreSelectors: ['.no-drag', '.button'],
|
|
75
|
+
enableHighDPI: true,
|
|
76
|
+
smoothDrag: true
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// 方法1: 设置整个区域为可拖拽,并自动忽略交互元素
|
|
80
|
+
setupDraggableArea('.title-bar');
|
|
81
|
+
|
|
82
|
+
// 方法2: 手动为元素启用拖拽
|
|
83
|
+
const header = document.getElementById('app-header');
|
|
84
|
+
enableDrag(header, { ignoreChildren: true });
|
|
85
|
+
|
|
86
|
+
// 方法3: 手动为元素禁用拖拽
|
|
87
|
+
const closeButton = document.getElementById('close-btn');
|
|
88
|
+
disableDrag(closeButton);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 在现代框架中使用
|
|
92
|
+
|
|
93
|
+
#### Vue 3 (Composition API)
|
|
94
|
+
|
|
95
|
+
```vue
|
|
96
|
+
<template>
|
|
97
|
+
<div class="app">
|
|
98
|
+
<div ref="titleBar" class="title-bar">
|
|
99
|
+
<h1>应用标题</h1>
|
|
100
|
+
<div class="window-controls">
|
|
101
|
+
<button @click="minimize">-</button>
|
|
102
|
+
<button @click="maximize">□</button>
|
|
103
|
+
<button @click="close">×</button>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
<div class="content">
|
|
107
|
+
<!-- 应用内容 -->
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</template>
|
|
111
|
+
|
|
112
|
+
<script setup>
|
|
113
|
+
import { ref, onMounted } from 'vue';
|
|
114
|
+
import { setupDraggableArea } from 'electron-drag-plus/dist/renderer';
|
|
115
|
+
|
|
116
|
+
// 使用 ref 获取DOM元素
|
|
117
|
+
const titleBar = ref(null);
|
|
118
|
+
|
|
119
|
+
// 窗口控制函数
|
|
120
|
+
const minimize = () => {
|
|
121
|
+
window.electron.ipcRenderer.send('window:minimize');
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const maximize = () => {
|
|
125
|
+
window.electron.ipcRenderer.send('window:maximize');
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const close = () => {
|
|
129
|
+
window.electron.ipcRenderer.send('window:close');
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// 组件挂载后设置拖拽区域
|
|
133
|
+
onMounted(() => {
|
|
134
|
+
if (titleBar.value) {
|
|
135
|
+
setupDraggableArea(titleBar.value);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
</script>
|
|
139
|
+
|
|
140
|
+
<style scoped>
|
|
141
|
+
.title-bar {
|
|
142
|
+
height: 40px;
|
|
143
|
+
background: #333;
|
|
144
|
+
color: white;
|
|
145
|
+
display: flex;
|
|
146
|
+
justify-content: space-between;
|
|
147
|
+
align-items: center;
|
|
148
|
+
padding: 0 10px;
|
|
149
|
+
user-select: none;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.window-controls button {
|
|
153
|
+
width: 30px;
|
|
154
|
+
height: 30px;
|
|
155
|
+
background: none;
|
|
156
|
+
border: none;
|
|
157
|
+
color: white;
|
|
158
|
+
cursor: pointer;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/* 确保按钮不会触发拖拽 */
|
|
162
|
+
.window-controls button {
|
|
163
|
+
-webkit-app-region: no-drag;
|
|
164
|
+
}
|
|
165
|
+
</style>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### Vue 3 组合式函数封装
|
|
169
|
+
|
|
170
|
+
```vue
|
|
171
|
+
<script setup>
|
|
172
|
+
import { ref, onMounted, onUnmounted } from 'vue';
|
|
173
|
+
import { setupDraggableArea, destroyDragPlus } from 'electron-drag-plus/dist/renderer';
|
|
174
|
+
|
|
175
|
+
// 创建可拖拽标题栏组件
|
|
176
|
+
const titleBar = ref(null);
|
|
177
|
+
|
|
178
|
+
// 组件挂载时初始化拖拽
|
|
179
|
+
onMounted(() => {
|
|
180
|
+
if (titleBar.value) {
|
|
181
|
+
setupDraggableArea(titleBar.value);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// 组件卸载时清理
|
|
186
|
+
onUnmounted(() => {
|
|
187
|
+
// 如果需要全局清理
|
|
188
|
+
// destroyDragPlus();
|
|
189
|
+
});
|
|
190
|
+
</script>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
#### React
|
|
194
|
+
|
|
195
|
+
```jsx
|
|
196
|
+
import React, { useEffect, useRef } from 'react';
|
|
197
|
+
import { setupDraggableArea } from 'electron-drag-plus/dist/renderer';
|
|
198
|
+
|
|
199
|
+
function App() {
|
|
200
|
+
const titleBarRef = useRef(null);
|
|
201
|
+
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
// 设置标题栏为可拖拽区域
|
|
204
|
+
if (titleBarRef.current) {
|
|
205
|
+
setupDraggableArea(titleBarRef.current);
|
|
206
|
+
}
|
|
207
|
+
}, []);
|
|
208
|
+
|
|
209
|
+
const minimize = () => {
|
|
210
|
+
window.electron.ipcRenderer.send('window:minimize');
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const maximize = () => {
|
|
214
|
+
window.electron.ipcRenderer.send('window:maximize');
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const close = () => {
|
|
218
|
+
window.electron.ipcRenderer.send('window:close');
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<div className="app">
|
|
223
|
+
<div ref={titleBarRef} className="title-bar">
|
|
224
|
+
<h1>应用标题</h1>
|
|
225
|
+
<div className="window-controls">
|
|
226
|
+
<button onClick={minimize}>-</button>
|
|
227
|
+
<button onClick={maximize}>□</button>
|
|
228
|
+
<button onClick={close}>×</button>
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
<div className="content">
|
|
232
|
+
{/* 应用内容 */}
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export default App;
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
#### React 自定义Hook
|
|
242
|
+
|
|
243
|
+
```jsx
|
|
244
|
+
import { useEffect } from 'react';
|
|
245
|
+
import { setupDraggableArea } from 'electron-drag-plus/dist/renderer';
|
|
246
|
+
|
|
247
|
+
// 创建一个自定义Hook来管理拖拽区域
|
|
248
|
+
export function useDraggable(ref) {
|
|
249
|
+
useEffect(() => {
|
|
250
|
+
if (ref.current) {
|
|
251
|
+
setupDraggableArea(ref.current);
|
|
252
|
+
}
|
|
253
|
+
}, [ref]);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// 使用示例
|
|
257
|
+
function DraggableTitleBar() {
|
|
258
|
+
const titleBarRef = useRef(null);
|
|
259
|
+
useDraggable(titleBarRef);
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<div ref={titleBarRef} className="title-bar">
|
|
263
|
+
<h1>拖拽标题栏</h1>
|
|
264
|
+
</div>
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
## API 参考
|
|
269
|
+
|
|
270
|
+
### 主进程 API
|
|
271
|
+
|
|
272
|
+
#### DragPlus 类
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
constructor(window: BrowserWindow, options?: DragPlusOptions);
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**参数**:
|
|
279
|
+
- `window`: Electron BrowserWindow 实例
|
|
280
|
+
- `options`: 配置选项
|
|
281
|
+
- `ignoreSelectors`: 忽略的CSS选择器数组
|
|
282
|
+
- `enableHighDPI`: 是否启用高DPI支持
|
|
283
|
+
- `smoothDrag`: 是否启用平滑拖拽
|
|
284
|
+
|
|
285
|
+
**方法**:
|
|
286
|
+
|
|
287
|
+
- `enableDrag(elementSelector: string)`: 为指定选择器的元素启用拖拽
|
|
288
|
+
- `disableDrag(elementSelector: string)`: 为指定选择器的元素禁用拖拽
|
|
289
|
+
- `updateOptions(newOptions: Partial<DragPlusOptions>)`: 更新配置选项
|
|
290
|
+
- `static getInstance(webContentsId: number)`: 获取特定webContents的DragPlus实例
|
|
291
|
+
|
|
292
|
+
### 渲染进程 API
|
|
293
|
+
|
|
294
|
+
#### 初始化
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
function initDragPlus(options?: RendererDragOptions): void;
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
**参数**:
|
|
301
|
+
- `options`: 配置选项,与主进程相同
|
|
302
|
+
|
|
303
|
+
#### 拖拽管理
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
// 设置可拖拽区域,自动忽略交互元素
|
|
307
|
+
function setupDraggableArea(container: HTMLElement | string): void;
|
|
308
|
+
|
|
309
|
+
// 为元素启用拖拽
|
|
310
|
+
function enableDrag(element: HTMLElement | string, options?: { ignoreChildren?: boolean }): void;
|
|
311
|
+
|
|
312
|
+
// 为元素禁用拖拽
|
|
313
|
+
function disableDrag(element: HTMLElement | string): void;
|
|
314
|
+
|
|
315
|
+
// 更新配置选项
|
|
316
|
+
function updateDragPlusOptions(options: Partial<RendererDragOptions>): void;
|
|
317
|
+
|
|
318
|
+
// 销毁拖拽管理器
|
|
319
|
+
function destroyDragPlus(): void;
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## 常见问题
|
|
323
|
+
|
|
324
|
+
### 1. 拖拽区域内的按钮无法点击
|
|
325
|
+
|
|
326
|
+
确保为按钮元素设置了`no-drag`样式:
|
|
327
|
+
|
|
328
|
+
```css
|
|
329
|
+
.button {
|
|
330
|
+
-webkit-app-region: no-drag;
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
或者使用`setupDraggableArea`函数,它会自动为交互元素添加`no-drag`。
|
|
335
|
+
|
|
336
|
+
### 2. 在高DPI显示器上拖拽仍然有问题
|
|
337
|
+
|
|
338
|
+
确保在创建`DragPlus`实例时启用了高DPI支持:
|
|
339
|
+
|
|
340
|
+
```javascript
|
|
341
|
+
const dragPlus = new DragPlus(win, {
|
|
342
|
+
enableHighDPI: true
|
|
343
|
+
});
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### 3. 窗口拖拽时仍然有抖动
|
|
347
|
+
|
|
348
|
+
尝试调整`smoothDrag`选项,或者检查是否有其他事件监听器干扰拖拽行为:
|
|
349
|
+
|
|
350
|
+
```javascript
|
|
351
|
+
const dragPlus = new DragPlus(win, {
|
|
352
|
+
smoothDrag: true
|
|
353
|
+
});
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## 开发
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
# 安装依赖
|
|
360
|
+
pnpm install
|
|
361
|
+
|
|
362
|
+
# 开发模式
|
|
363
|
+
pnpm run dev
|
|
364
|
+
|
|
365
|
+
# 构建
|
|
366
|
+
pnpm run build
|
|
367
|
+
|
|
368
|
+
# 运行测试
|
|
369
|
+
pnpm run test
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## 许可证
|
|
373
|
+
|
|
374
|
+
[MIT](LICENSE)
|
|
375
|
+
|
|
376
|
+
## 贡献
|
|
377
|
+
|
|
378
|
+
欢迎提交Issue和Pull Request!
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/example.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
// 主进程使用示例
|
|
4
|
+
const electron_1 = require("electron");
|
|
5
|
+
const index_1 = require("./index");
|
|
6
|
+
// 创建窗口时初始化拖拽增强
|
|
7
|
+
function createWindow() {
|
|
8
|
+
const win = new electron_1.BrowserWindow({
|
|
9
|
+
width: 800,
|
|
10
|
+
height: 600,
|
|
11
|
+
frame: false, // 无边框窗口
|
|
12
|
+
webPreferences: {
|
|
13
|
+
nodeIntegration: true,
|
|
14
|
+
contextIsolation: false
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
// 初始化拖拽增强
|
|
18
|
+
const dragPlus = new index_1.DragPlus(win, {
|
|
19
|
+
ignoreSelectors: ['.no-drag', '#close-button'],
|
|
20
|
+
enableHighDPI: true,
|
|
21
|
+
smoothDrag: true
|
|
22
|
+
});
|
|
23
|
+
// 手动启用特定元素的拖拽
|
|
24
|
+
dragPlus.enableDrag('.title-bar');
|
|
25
|
+
// 手动禁用特定元素的拖拽
|
|
26
|
+
dragPlus.disableDrag('.window-controls');
|
|
27
|
+
win.loadFile('index.html');
|
|
28
|
+
}
|
|
29
|
+
electron_1.app.whenReady().then(createWindow);
|
|
30
|
+
// 渲染进程使用示例
|
|
31
|
+
/*
|
|
32
|
+
// 在渲染进程中
|
|
33
|
+
import { initDragPlus, setupDraggableArea, enableDrag, disableDrag } from 'electron-drag-plus/dist/renderer';
|
|
34
|
+
|
|
35
|
+
// 初始化拖拽功能
|
|
36
|
+
initDragPlus({
|
|
37
|
+
ignoreSelectors: ['.no-drag', '.button'],
|
|
38
|
+
enableHighDPI: true,
|
|
39
|
+
smoothDrag: true
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// 方法1: 设置整个区域为可拖拽,并自动忽略交互元素
|
|
43
|
+
setupDraggableArea('.title-bar');
|
|
44
|
+
|
|
45
|
+
// 方法2: 手动为元素启用拖拽
|
|
46
|
+
const header = document.getElementById('app-header');
|
|
47
|
+
enableDrag(header, { ignoreChildren: true });
|
|
48
|
+
|
|
49
|
+
// 方法3: 手动为元素禁用拖拽
|
|
50
|
+
const closeButton = document.getElementById('close-btn');
|
|
51
|
+
disableDrag(closeButton);
|
|
52
|
+
|
|
53
|
+
// 在Vue组件中使用示例
|
|
54
|
+
// export default {
|
|
55
|
+
// mounted() {
|
|
56
|
+
// setupDraggableArea(this.$refs.titleBar);
|
|
57
|
+
// }
|
|
58
|
+
// }
|
|
59
|
+
|
|
60
|
+
// 在React组件中使用示例
|
|
61
|
+
// import { useEffect, useRef } from 'react';
|
|
62
|
+
//
|
|
63
|
+
// export function TitleBar() {
|
|
64
|
+
// const titleBarRef = useRef(null);
|
|
65
|
+
//
|
|
66
|
+
// useEffect(() => {
|
|
67
|
+
// setupDraggableArea(titleBarRef.current);
|
|
68
|
+
// }, []);
|
|
69
|
+
//
|
|
70
|
+
// return (
|
|
71
|
+
// <div ref={titleBarRef}>
|
|
72
|
+
// <h1>应用标题</h1>
|
|
73
|
+
// <button className="window-control">关闭</button>
|
|
74
|
+
// </div>
|
|
75
|
+
// );
|
|
76
|
+
// }
|
|
77
|
+
*/
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { BrowserWindow } from 'electron';
|
|
2
|
+
/**
|
|
3
|
+
* 拖拽配置选项
|
|
4
|
+
*/
|
|
5
|
+
export interface DragPlusOptions {
|
|
6
|
+
/**
|
|
7
|
+
* 需要忽略鼠标事件的选择器
|
|
8
|
+
*/
|
|
9
|
+
ignoreSelectors?: string[];
|
|
10
|
+
/**
|
|
11
|
+
* 是否启用高DPI支持,解决不同分辨率和缩放问题
|
|
12
|
+
* @default true
|
|
13
|
+
*/
|
|
14
|
+
enableHighDPI?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* 是否启用平滑拖拽,解决窗口抖动问题
|
|
17
|
+
* @default true
|
|
18
|
+
*/
|
|
19
|
+
smoothDrag?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* DragPlus类 - 增强版Electron窗口拖拽库
|
|
23
|
+
*/
|
|
24
|
+
export declare class DragPlus {
|
|
25
|
+
private static instances;
|
|
26
|
+
private window;
|
|
27
|
+
private webContents;
|
|
28
|
+
private options;
|
|
29
|
+
private isDragging;
|
|
30
|
+
private lastMousePosition;
|
|
31
|
+
private originalResizableState;
|
|
32
|
+
/**
|
|
33
|
+
* 构造函数
|
|
34
|
+
* @param window Electron窗口实例
|
|
35
|
+
* @param options 配置选项
|
|
36
|
+
*/
|
|
37
|
+
constructor(window: BrowserWindow, options?: DragPlusOptions);
|
|
38
|
+
/**
|
|
39
|
+
* 设置拖拽功能
|
|
40
|
+
*/
|
|
41
|
+
private setup;
|
|
42
|
+
/**
|
|
43
|
+
* 获取特定webContents的DragPlus实例
|
|
44
|
+
* @param webContentsId webContents的ID
|
|
45
|
+
* @returns DragPlus实例或undefined
|
|
46
|
+
*/
|
|
47
|
+
static getInstance(webContentsId: number): DragPlus | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* 启用元素拖拽
|
|
50
|
+
* @param elementSelector CSS选择器
|
|
51
|
+
*/
|
|
52
|
+
enableDrag(elementSelector: string): void;
|
|
53
|
+
/**
|
|
54
|
+
* 禁用元素拖拽
|
|
55
|
+
* @param elementSelector CSS选择器
|
|
56
|
+
*/
|
|
57
|
+
disableDrag(elementSelector: string): void;
|
|
58
|
+
/**
|
|
59
|
+
* 更新配置
|
|
60
|
+
* @param newOptions 新的配置选项
|
|
61
|
+
*/
|
|
62
|
+
updateOptions(newOptions: Partial<DragPlusOptions>): void;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 渲染进程使用的工具函数集合
|
|
66
|
+
*/
|
|
67
|
+
export declare const renderer: {
|
|
68
|
+
/**
|
|
69
|
+
* 为元素添加拖拽功能
|
|
70
|
+
* @param element 元素或元素选择器
|
|
71
|
+
* @param options 配置选项
|
|
72
|
+
*/
|
|
73
|
+
enableDrag(element: HTMLElement | string, options?: {
|
|
74
|
+
ignoreChildren?: boolean;
|
|
75
|
+
}): void;
|
|
76
|
+
/**
|
|
77
|
+
* 为元素禁用拖拽功能
|
|
78
|
+
* @param element 元素或元素选择器
|
|
79
|
+
*/
|
|
80
|
+
disableDrag(element: HTMLElement | string): void;
|
|
81
|
+
/**
|
|
82
|
+
* 设置可拖拽区域,自动忽略交互元素
|
|
83
|
+
* @param container 容器元素或选择器
|
|
84
|
+
*/
|
|
85
|
+
setupDraggableArea(container: HTMLElement | string): void;
|
|
86
|
+
};
|
|
87
|
+
declare const dragPlus: {
|
|
88
|
+
DragPlus: typeof DragPlus;
|
|
89
|
+
renderer: {
|
|
90
|
+
/**
|
|
91
|
+
* 为元素添加拖拽功能
|
|
92
|
+
* @param element 元素或元素选择器
|
|
93
|
+
* @param options 配置选项
|
|
94
|
+
*/
|
|
95
|
+
enableDrag(element: HTMLElement | string, options?: {
|
|
96
|
+
ignoreChildren?: boolean;
|
|
97
|
+
}): void;
|
|
98
|
+
/**
|
|
99
|
+
* 为元素禁用拖拽功能
|
|
100
|
+
* @param element 元素或元素选择器
|
|
101
|
+
*/
|
|
102
|
+
disableDrag(element: HTMLElement | string): void;
|
|
103
|
+
/**
|
|
104
|
+
* 设置可拖拽区域,自动忽略交互元素
|
|
105
|
+
* @param container 容器元素或选择器
|
|
106
|
+
*/
|
|
107
|
+
setupDraggableArea(container: HTMLElement | string): void;
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
export default dragPlus;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderer = exports.DragPlus = void 0;
|
|
4
|
+
const electron_1 = require("electron");
|
|
5
|
+
/**
|
|
6
|
+
* DragPlus类 - 增强版Electron窗口拖拽库
|
|
7
|
+
*/
|
|
8
|
+
class DragPlus {
|
|
9
|
+
/**
|
|
10
|
+
* 构造函数
|
|
11
|
+
* @param window Electron窗口实例
|
|
12
|
+
* @param options 配置选项
|
|
13
|
+
*/
|
|
14
|
+
constructor(window, options = {}) {
|
|
15
|
+
this.isDragging = false;
|
|
16
|
+
this.lastMousePosition = null;
|
|
17
|
+
this.originalResizableState = null;
|
|
18
|
+
this.window = window;
|
|
19
|
+
this.webContents = window.webContents;
|
|
20
|
+
this.options = {
|
|
21
|
+
ignoreSelectors: options.ignoreSelectors || [],
|
|
22
|
+
enableHighDPI: options.enableHighDPI ?? true,
|
|
23
|
+
smoothDrag: options.smoothDrag ?? true
|
|
24
|
+
};
|
|
25
|
+
// 存储实例引用
|
|
26
|
+
DragPlus.instances.set(this.webContents.id, this);
|
|
27
|
+
this.setup();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 设置拖拽功能
|
|
31
|
+
*/
|
|
32
|
+
setup() {
|
|
33
|
+
// 向渲染进程发送配置信息
|
|
34
|
+
this.webContents.on('did-finish-load', () => {
|
|
35
|
+
this.webContents.send('drag-plus:config', this.options);
|
|
36
|
+
});
|
|
37
|
+
// 处理拖拽事件
|
|
38
|
+
electron_1.ipcMain.on('drag-plus:start', (event, data) => {
|
|
39
|
+
if (this.options.smoothDrag) {
|
|
40
|
+
this.isDragging = true;
|
|
41
|
+
this.lastMousePosition = { x: data.x, y: data.y };
|
|
42
|
+
// 保存原始的可缩放状态
|
|
43
|
+
this.originalResizableState = this.window.isResizable();
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// 如果不使用平滑拖拽,则使用原生方式
|
|
47
|
+
this.window.setIgnoreMouseEvents(false, { forward: true });
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
electron_1.ipcMain.on('drag-plus:drag', (event, data) => {
|
|
51
|
+
if (this.isDragging && this.options.smoothDrag && this.lastMousePosition) {
|
|
52
|
+
const winBounds = this.window.getBounds();
|
|
53
|
+
const x = winBounds.x + (data.x - this.lastMousePosition.x);
|
|
54
|
+
const y = winBounds.y + (data.y - this.lastMousePosition.y);
|
|
55
|
+
// 应用优化的拖拽移动方法,解决窗口抖动问题
|
|
56
|
+
// 1. 记住当前尺寸
|
|
57
|
+
const size = this.window.getSize();
|
|
58
|
+
// 2. 关闭缩放
|
|
59
|
+
this.window.setResizable(false);
|
|
60
|
+
// 3. 设置新坐标
|
|
61
|
+
this.window.setPosition(x, y, false);
|
|
62
|
+
// 4. 强制写回尺寸
|
|
63
|
+
this.window.setSize(size[0], size[1], false);
|
|
64
|
+
// 5. 重新允许缩放 (移动结束时恢复,而不是每次移动都恢复)
|
|
65
|
+
this.lastMousePosition = { x: data.x, y: data.y };
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
electron_1.ipcMain.on('drag-plus:stop', () => {
|
|
69
|
+
this.isDragging = false;
|
|
70
|
+
this.lastMousePosition = null;
|
|
71
|
+
// 恢复原始的可缩放状态
|
|
72
|
+
if (this.originalResizableState !== null) {
|
|
73
|
+
this.window.setResizable(this.originalResizableState);
|
|
74
|
+
this.originalResizableState = null;
|
|
75
|
+
}
|
|
76
|
+
this.window.setIgnoreMouseEvents(false);
|
|
77
|
+
});
|
|
78
|
+
// 清理
|
|
79
|
+
this.window.on('closed', () => {
|
|
80
|
+
DragPlus.instances.delete(this.webContents.id);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 获取特定webContents的DragPlus实例
|
|
85
|
+
* @param webContentsId webContents的ID
|
|
86
|
+
* @returns DragPlus实例或undefined
|
|
87
|
+
*/
|
|
88
|
+
static getInstance(webContentsId) {
|
|
89
|
+
return DragPlus.instances.get(webContentsId);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 启用元素拖拽
|
|
93
|
+
* @param elementSelector CSS选择器
|
|
94
|
+
*/
|
|
95
|
+
enableDrag(elementSelector) {
|
|
96
|
+
this.webContents.executeJavaScript(`
|
|
97
|
+
(function() {
|
|
98
|
+
const elements = document.querySelectorAll('${elementSelector.replace(/'/g, "\\'")}');
|
|
99
|
+
elements.forEach(element => {
|
|
100
|
+
element.style.appRegion = 'drag';
|
|
101
|
+
});
|
|
102
|
+
})();
|
|
103
|
+
`);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 禁用元素拖拽
|
|
107
|
+
* @param elementSelector CSS选择器
|
|
108
|
+
*/
|
|
109
|
+
disableDrag(elementSelector) {
|
|
110
|
+
this.webContents.executeJavaScript(`
|
|
111
|
+
(function() {
|
|
112
|
+
const elements = document.querySelectorAll('${elementSelector.replace(/'/g, "\\'")}');
|
|
113
|
+
elements.forEach(element => {
|
|
114
|
+
element.style.appRegion = 'no-drag';
|
|
115
|
+
});
|
|
116
|
+
})();
|
|
117
|
+
`);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 更新配置
|
|
121
|
+
* @param newOptions 新的配置选项
|
|
122
|
+
*/
|
|
123
|
+
updateOptions(newOptions) {
|
|
124
|
+
this.options = { ...this.options, ...newOptions };
|
|
125
|
+
this.webContents.send('drag-plus:config', this.options);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.DragPlus = DragPlus;
|
|
129
|
+
DragPlus.instances = new Map();
|
|
130
|
+
/**
|
|
131
|
+
* 渲染进程使用的工具函数集合
|
|
132
|
+
*/
|
|
133
|
+
exports.renderer = {
|
|
134
|
+
/**
|
|
135
|
+
* 为元素添加拖拽功能
|
|
136
|
+
* @param element 元素或元素选择器
|
|
137
|
+
* @param options 配置选项
|
|
138
|
+
*/
|
|
139
|
+
enableDrag(element, options) {
|
|
140
|
+
const target = typeof element === 'string' ?
|
|
141
|
+
document.querySelector(element) : element;
|
|
142
|
+
if (target && target instanceof HTMLElement) {
|
|
143
|
+
target.style.appRegion = 'drag';
|
|
144
|
+
// 处理需要忽略的子元素
|
|
145
|
+
if (options?.ignoreChildren) {
|
|
146
|
+
const interactiveElements = target.querySelectorAll('button, input, select, textarea, a, [onclick]');
|
|
147
|
+
interactiveElements.forEach(child => {
|
|
148
|
+
child.style.appRegion = 'no-drag';
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
/**
|
|
154
|
+
* 为元素禁用拖拽功能
|
|
155
|
+
* @param element 元素或元素选择器
|
|
156
|
+
*/
|
|
157
|
+
disableDrag(element) {
|
|
158
|
+
const target = typeof element === 'string' ?
|
|
159
|
+
document.querySelector(element) : element;
|
|
160
|
+
if (target && target instanceof HTMLElement) {
|
|
161
|
+
target.style.appRegion = 'no-drag';
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
/**
|
|
165
|
+
* 设置可拖拽区域,自动忽略交互元素
|
|
166
|
+
* @param container 容器元素或选择器
|
|
167
|
+
*/
|
|
168
|
+
setupDraggableArea(container) {
|
|
169
|
+
const target = typeof container === 'string' ?
|
|
170
|
+
document.querySelector(container) : container;
|
|
171
|
+
if (target && target instanceof HTMLElement) {
|
|
172
|
+
// 设置整个容器为可拖拽
|
|
173
|
+
target.style.appRegion = 'drag';
|
|
174
|
+
// 为所有交互元素设置no-drag
|
|
175
|
+
const interactiveElements = target.querySelectorAll('button, input, select, textarea, a, [onclick], [href], [tabindex]:not([tabindex="-1"])');
|
|
176
|
+
interactiveElements.forEach(element => {
|
|
177
|
+
element.style.appRegion = 'no-drag';
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
// 默认导出
|
|
183
|
+
const dragPlus = {
|
|
184
|
+
DragPlus,
|
|
185
|
+
renderer: exports.renderer
|
|
186
|
+
};
|
|
187
|
+
exports.default = dragPlus;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 渲染进程的拖拽配置选项
|
|
3
|
+
*/
|
|
4
|
+
export interface RendererDragOptions {
|
|
5
|
+
/**
|
|
6
|
+
* 需要忽略鼠标事件的选择器
|
|
7
|
+
*/
|
|
8
|
+
ignoreSelectors?: string[];
|
|
9
|
+
/**
|
|
10
|
+
* 是否启用高DPI支持
|
|
11
|
+
*/
|
|
12
|
+
enableHighDPI?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* 是否启用平滑拖拽
|
|
15
|
+
*/
|
|
16
|
+
smoothDrag?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 初始化拖拽管理器
|
|
20
|
+
* @param options 配置选项
|
|
21
|
+
*/
|
|
22
|
+
export declare function initDragPlus(options?: RendererDragOptions): void;
|
|
23
|
+
/**
|
|
24
|
+
* 为元素添加拖拽功能
|
|
25
|
+
* @param element 元素或元素选择器
|
|
26
|
+
* @param options 配置选项
|
|
27
|
+
*/
|
|
28
|
+
export declare function enableDrag(element: HTMLElement | string, options?: {
|
|
29
|
+
ignoreChildren?: boolean;
|
|
30
|
+
}): void;
|
|
31
|
+
/**
|
|
32
|
+
* 为元素禁用拖拽功能
|
|
33
|
+
* @param element 元素或元素选择器
|
|
34
|
+
*/
|
|
35
|
+
export declare function disableDrag(element: HTMLElement | string): void;
|
|
36
|
+
/**
|
|
37
|
+
* 设置可拖拽区域,自动忽略交互元素
|
|
38
|
+
* @param container 容器元素或选择器
|
|
39
|
+
*/
|
|
40
|
+
export declare function setupDraggableArea(container: HTMLElement | string): void;
|
|
41
|
+
/**
|
|
42
|
+
* 更新拖拽配置
|
|
43
|
+
* @param options 新的配置选项
|
|
44
|
+
*/
|
|
45
|
+
export declare function updateDragPlusOptions(options: Partial<RendererDragOptions>): void;
|
|
46
|
+
/**
|
|
47
|
+
* 销毁拖拽管理器
|
|
48
|
+
*/
|
|
49
|
+
export declare function destroyDragPlus(): void;
|
|
50
|
+
declare const _default: {
|
|
51
|
+
init: typeof initDragPlus;
|
|
52
|
+
enableDrag: typeof enableDrag;
|
|
53
|
+
disableDrag: typeof disableDrag;
|
|
54
|
+
setupDraggableArea: typeof setupDraggableArea;
|
|
55
|
+
updateOptions: typeof updateDragPlusOptions;
|
|
56
|
+
destroy: typeof destroyDragPlus;
|
|
57
|
+
};
|
|
58
|
+
export default _default;
|
package/dist/renderer.js
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initDragPlus = initDragPlus;
|
|
4
|
+
exports.enableDrag = enableDrag;
|
|
5
|
+
exports.disableDrag = disableDrag;
|
|
6
|
+
exports.setupDraggableArea = setupDraggableArea;
|
|
7
|
+
exports.updateDragPlusOptions = updateDragPlusOptions;
|
|
8
|
+
exports.destroyDragPlus = destroyDragPlus;
|
|
9
|
+
const electron_1 = require("electron");
|
|
10
|
+
/**
|
|
11
|
+
* 拖拽管理器类
|
|
12
|
+
*/
|
|
13
|
+
class DragManager {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.options = {
|
|
16
|
+
ignoreSelectors: [],
|
|
17
|
+
enableHighDPI: true,
|
|
18
|
+
smoothDrag: true
|
|
19
|
+
};
|
|
20
|
+
this.isDragging = false;
|
|
21
|
+
this.dragElement = null;
|
|
22
|
+
this.startX = 0;
|
|
23
|
+
this.startY = 0;
|
|
24
|
+
this.setupIPC();
|
|
25
|
+
this.setupEventListeners();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 设置IPC通信
|
|
29
|
+
*/
|
|
30
|
+
setupIPC() {
|
|
31
|
+
electron_1.ipcRenderer.on('drag-plus:config', (event, config) => {
|
|
32
|
+
this.options = { ...this.options, ...config };
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 设置事件监听器
|
|
37
|
+
*/
|
|
38
|
+
setupEventListeners() {
|
|
39
|
+
document.addEventListener('mousedown', this.handleMouseDown.bind(this), true);
|
|
40
|
+
document.addEventListener('mousemove', this.handleMouseMove.bind(this), true);
|
|
41
|
+
document.addEventListener('mouseup', this.handleMouseUp.bind(this), true);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 检查元素是否应该忽略拖拽
|
|
45
|
+
* @param element 要检查的元素
|
|
46
|
+
* @returns 是否应该忽略
|
|
47
|
+
*/
|
|
48
|
+
shouldIgnore(element) {
|
|
49
|
+
// 检查元素自身是否是no-drag
|
|
50
|
+
if (element.style.appRegion === 'no-drag') {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
// 检查元素是否匹配忽略选择器
|
|
54
|
+
for (const selector of this.options.ignoreSelectors || []) {
|
|
55
|
+
if (element.matches(selector)) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// 检查祖先元素是否是no-drag
|
|
60
|
+
let parent = element.parentElement;
|
|
61
|
+
while (parent) {
|
|
62
|
+
if (parent.style.appRegion === 'no-drag') {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
parent = parent.parentElement;
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 鼠标按下事件处理
|
|
71
|
+
*/
|
|
72
|
+
handleMouseDown(e) {
|
|
73
|
+
const target = e.target;
|
|
74
|
+
// 检查元素是否是可拖拽区域且不应该被忽略
|
|
75
|
+
if (target.style.appRegion === 'drag' && !this.shouldIgnore(target)) {
|
|
76
|
+
this.isDragging = true;
|
|
77
|
+
this.dragElement = target;
|
|
78
|
+
this.startX = e.screenX;
|
|
79
|
+
this.startY = e.screenY;
|
|
80
|
+
// 通知主进程开始拖拽
|
|
81
|
+
electron_1.ipcRenderer.send('drag-plus:start', {
|
|
82
|
+
x: e.screenX,
|
|
83
|
+
y: e.screenY
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 鼠标移动事件处理
|
|
89
|
+
*/
|
|
90
|
+
handleMouseMove(e) {
|
|
91
|
+
if (this.isDragging && this.dragElement) {
|
|
92
|
+
// 计算鼠标移动距离
|
|
93
|
+
const deltaX = e.screenX - this.startX;
|
|
94
|
+
const deltaY = e.screenY - this.startY;
|
|
95
|
+
// 只有在移动超过一定阈值时才发送拖拽事件,减少抖动
|
|
96
|
+
if (Math.abs(deltaX) > 2 || Math.abs(deltaY) > 2) {
|
|
97
|
+
electron_1.ipcRenderer.send('drag-plus:drag', {
|
|
98
|
+
x: e.screenX,
|
|
99
|
+
y: e.screenY
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 鼠标释放事件处理
|
|
106
|
+
*/
|
|
107
|
+
handleMouseUp() {
|
|
108
|
+
if (this.isDragging) {
|
|
109
|
+
this.isDragging = false;
|
|
110
|
+
this.dragElement = null;
|
|
111
|
+
// 通知主进程结束拖拽
|
|
112
|
+
electron_1.ipcRenderer.send('drag-plus:stop');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 更新配置选项
|
|
117
|
+
* @param options 新的配置选项
|
|
118
|
+
*/
|
|
119
|
+
updateOptions(options) {
|
|
120
|
+
this.options = { ...this.options, ...options };
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* 销毁拖拽管理器
|
|
124
|
+
*/
|
|
125
|
+
destroy() {
|
|
126
|
+
document.removeEventListener('mousedown', this.handleMouseDown.bind(this), true);
|
|
127
|
+
document.removeEventListener('mousemove', this.handleMouseMove.bind(this), true);
|
|
128
|
+
document.removeEventListener('mouseup', this.handleMouseUp.bind(this), true);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// 创建全局拖拽管理器实例
|
|
132
|
+
let dragManager = null;
|
|
133
|
+
/**
|
|
134
|
+
* 初始化拖拽管理器
|
|
135
|
+
* @param options 配置选项
|
|
136
|
+
*/
|
|
137
|
+
function initDragPlus(options = {}) {
|
|
138
|
+
if (!dragManager) {
|
|
139
|
+
dragManager = new DragManager();
|
|
140
|
+
}
|
|
141
|
+
dragManager.updateOptions(options);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 为元素添加拖拽功能
|
|
145
|
+
* @param element 元素或元素选择器
|
|
146
|
+
* @param options 配置选项
|
|
147
|
+
*/
|
|
148
|
+
function enableDrag(element, options) {
|
|
149
|
+
const target = typeof element === 'string' ?
|
|
150
|
+
document.querySelector(element) : element;
|
|
151
|
+
if (target && target instanceof HTMLElement) {
|
|
152
|
+
target.style.appRegion = 'drag';
|
|
153
|
+
// 处理需要忽略的子元素
|
|
154
|
+
if (options?.ignoreChildren) {
|
|
155
|
+
const interactiveElements = target.querySelectorAll('button, input, select, textarea, a, [onclick]');
|
|
156
|
+
interactiveElements.forEach(child => {
|
|
157
|
+
child.style.appRegion = 'no-drag';
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* 为元素禁用拖拽功能
|
|
164
|
+
* @param element 元素或元素选择器
|
|
165
|
+
*/
|
|
166
|
+
function disableDrag(element) {
|
|
167
|
+
const target = typeof element === 'string' ?
|
|
168
|
+
document.querySelector(element) : element;
|
|
169
|
+
if (target && target instanceof HTMLElement) {
|
|
170
|
+
target.style.appRegion = 'no-drag';
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* 设置可拖拽区域,自动忽略交互元素
|
|
175
|
+
* @param container 容器元素或选择器
|
|
176
|
+
*/
|
|
177
|
+
function setupDraggableArea(container) {
|
|
178
|
+
const target = typeof container === 'string' ?
|
|
179
|
+
document.querySelector(container) : container;
|
|
180
|
+
if (target && target instanceof HTMLElement) {
|
|
181
|
+
// 设置整个容器为可拖拽
|
|
182
|
+
target.style.appRegion = 'drag';
|
|
183
|
+
// 为所有交互元素设置no-drag
|
|
184
|
+
const interactiveElements = target.querySelectorAll('button, input, select, textarea, a, [onclick], [href], [tabindex]:not([tabindex="-1"])');
|
|
185
|
+
interactiveElements.forEach(element => {
|
|
186
|
+
element.style.appRegion = 'no-drag';
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* 更新拖拽配置
|
|
192
|
+
* @param options 新的配置选项
|
|
193
|
+
*/
|
|
194
|
+
function updateDragPlusOptions(options) {
|
|
195
|
+
if (dragManager) {
|
|
196
|
+
dragManager.updateOptions(options);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* 销毁拖拽管理器
|
|
201
|
+
*/
|
|
202
|
+
function destroyDragPlus() {
|
|
203
|
+
if (dragManager) {
|
|
204
|
+
dragManager.destroy();
|
|
205
|
+
dragManager = null;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// 默认导出渲染进程API
|
|
209
|
+
exports.default = {
|
|
210
|
+
init: initDragPlus,
|
|
211
|
+
enableDrag,
|
|
212
|
+
disableDrag,
|
|
213
|
+
setupDraggableArea,
|
|
214
|
+
updateOptions: updateDragPlusOptions,
|
|
215
|
+
destroy: destroyDragPlus
|
|
216
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "electron-drag-plus",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "增强版Electron窗口拖拽库,解决窗口抖动、不同分辨率/缩放导致的闪屏问题,并支持拖拽区域忽略鼠标事件",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"dev": "tsc --watch",
|
|
10
|
+
"prepublishOnly": "npm run build",
|
|
11
|
+
"test": "jest"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"electron",
|
|
15
|
+
"drag",
|
|
16
|
+
"window",
|
|
17
|
+
"electron-drag",
|
|
18
|
+
"electron-window",
|
|
19
|
+
"no-drag",
|
|
20
|
+
"resize",
|
|
21
|
+
"electron-window-drag"
|
|
22
|
+
],
|
|
23
|
+
"author": "",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"packageManager": "pnpm@10.16.1",
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^20.0.0",
|
|
28
|
+
"jest": "^29.0.0",
|
|
29
|
+
"typescript": "^5.0.0"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist/**/*",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE"
|
|
35
|
+
],
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/yourusername/electron-drag-plus.git"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/yourusername/electron-drag-plus/issues"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/yourusername/electron-drag-plus#readme",
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"electron": "^39.0.0"
|
|
46
|
+
}
|
|
47
|
+
}
|