@lynker-desktop/electron-window-manager 0.0.9-alpha.2 → 0.0.9-alpha.20

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/main/index.js CHANGED
@@ -69,30 +69,43 @@ class WindowsManager {
69
69
  * - 不带点的(如 example.com)只匹配主域名。
70
70
  * - 'localhost'、'127.0.0.1'、'::1' 以及局域网 IP(如 192.168.x.x、10.x.x.x、172.16.x.x~172.31.x.x)都视为本地白名单。
71
71
  */
72
- constructor(preload, loadingViewUrl, errorViewUrl, preloadWebContentsUrl, webviewDomainWhiteList) {
72
+ constructor(preload, loadingViewUrl, errorViewUrl, preloadWebContentsConfig, webviewDomainWhiteList) {
73
+ // 预加载的窗口
73
74
  this.preloadedBW = null;
75
+ // 预加载的窗口(无边框,有按钮)
74
76
  this.preloadedBW_FramelessWithButtons = null;
77
+ // 预加载的窗口(无边框,无按钮)
75
78
  this.preloadedBW_FramelessNoButtons = null;
79
+ // 预加载的浏览器视图
76
80
  this.preloadedBV = null;
77
81
  this.preloading = false;
78
82
  this.webviewDomainWhiteList = [];
83
+ // 创建队列相关属性
84
+ this.createQueue = [];
85
+ this.isCreating = false;
79
86
  this.preload = preload;
80
87
  this.windows = new Map();
81
88
  this.loadingViewUrl = `${loadingViewUrl ?? ''}`;
82
89
  this.errorViewUrl = `${errorViewUrl ?? ''}`;
83
- this.preloadWebContentsUrl = `${preloadWebContentsUrl ?? ''}`;
90
+ this.preloadWebContentsConfig = preloadWebContentsConfig;
84
91
  this.webviewDomainWhiteList = webviewDomainWhiteList || [];
85
- log('log', 'preloadWebContentsUrl: ', this.preloadWebContentsUrl);
86
- if (this.preloadWebContentsUrl) {
87
- electron.app.on('ready', () => {
88
- this._preloadInstances();
92
+ log('log', 'preloadWebContentsConfig: ', this.preloadWebContentsConfig);
93
+ if (this.preloadWebContentsConfig) {
94
+ electron.app.whenReady().then(() => {
95
+ if (this.preloadWebContentsConfig) {
96
+ this.setPreloadWebContentsConfig(this.preloadWebContentsConfig);
97
+ }
89
98
  });
90
99
  }
91
100
  }
92
- setPreloadWebContentsUrl(preloadWebContentsUrl) {
101
+ /**
102
+ * 设置预加载的webContents配置
103
+ * @param preloadWebContentsConfig 预加载的webContents配置
104
+ */
105
+ setPreloadWebContentsConfig(preloadWebContentsConfig) {
93
106
  try {
94
- this.preloadWebContentsUrl = preloadWebContentsUrl;
95
- if (this.preloadWebContentsUrl) {
107
+ this.preloadWebContentsConfig = preloadWebContentsConfig;
108
+ if (this.preloadWebContentsConfig) {
96
109
  this._preloadInstances();
97
110
  }
98
111
  else {
@@ -103,27 +116,65 @@ class WindowsManager {
103
116
  }
104
117
  }
105
118
  catch (error) {
106
- log('error', 'setPreloadWebContentsUrl error:', error);
119
+ log('error', 'setPreloadWebContentsConfig error:', error);
107
120
  }
108
121
  }
122
+ /**
123
+ * 预加载实例
124
+ */
109
125
  async _preloadInstances() {
110
126
  if (this.preloading)
111
127
  return;
112
128
  this.preloading = true;
113
129
  try {
114
- if (this.preloadWebContentsUrl) {
115
- this.preloadedBW = this.preloadedBW || await this._createPreloadBW({});
116
- this.preloadedBW_FramelessWithButtons = this.preloadedBW_FramelessWithButtons || await this._createPreloadBW({
117
- frame: false,
118
- transparent: true,
119
- titleBarStyle: 'hidden',
120
- });
121
- this.preloadedBW_FramelessNoButtons = this.preloadedBW_FramelessNoButtons || await this._createPreloadBW({
122
- frame: false,
123
- transparent: true,
124
- titleBarStyle: 'customButtonsOnHover',
125
- });
126
- this.preloadedBV = this.preloadedBV || await this._createPreloadBV();
130
+ if (this.preloadWebContentsConfig) {
131
+ log('log', 'preloadWebContentsConfig: ', this.preloadWebContentsConfig);
132
+ // 根据配置决定是否预加载普通窗口
133
+ if (this.preloadWebContentsConfig.enableBW !== false) {
134
+ if (!this.preloadedBW) {
135
+ this._createPreloadBW({}).then(i => {
136
+ this.preloadedBW = i;
137
+ log('log', 'init preloadedBW: ', !!this.preloadedBW);
138
+ });
139
+ }
140
+ }
141
+ // 根据配置决定是否预加载无边框有按钮的窗口
142
+ if (this.preloadWebContentsConfig.enableBW_FramelessWithButtons !== false) {
143
+ if (!this.preloadedBW_FramelessWithButtons) {
144
+ this._createPreloadBW({
145
+ frame: false,
146
+ // transparent: true,
147
+ autoHideMenuBar: true,
148
+ titleBarStyle: 'hidden',
149
+ }).then(i => {
150
+ this.preloadedBW_FramelessWithButtons = i;
151
+ log('log', 'init preloadedBW_FramelessWithButtons: ', !!this.preloadedBW_FramelessWithButtons);
152
+ });
153
+ }
154
+ }
155
+ // 根据配置决定是否预加载无边框无按钮的窗口
156
+ if (this.preloadWebContentsConfig.enableBW_FramelessNoButtons !== false) {
157
+ if (!this.preloadedBW_FramelessNoButtons) {
158
+ this._createPreloadBW({
159
+ frame: false,
160
+ // transparent: true,
161
+ autoHideMenuBar: true,
162
+ titleBarStyle: 'default',
163
+ }).then(i => {
164
+ this.preloadedBW_FramelessNoButtons = i;
165
+ log('log', 'init preloadedBW_FramelessNoButtons: ', !!this.preloadedBW_FramelessNoButtons);
166
+ });
167
+ }
168
+ }
169
+ // 根据配置决定是否预加载浏览器视图
170
+ if (this.preloadWebContentsConfig.enableBV !== false) {
171
+ if (!this.preloadedBV) {
172
+ this._createPreloadBV().then(i => {
173
+ this.preloadedBV = i;
174
+ log('log', 'init preloadedBV: ', !!this.preloadedBV);
175
+ });
176
+ }
177
+ }
127
178
  }
128
179
  }
129
180
  catch (e) {
@@ -131,23 +182,30 @@ class WindowsManager {
131
182
  }
132
183
  this.preloading = false;
133
184
  }
185
+ /**
186
+ * 创建预加载的窗口
187
+ * @param options 窗口选项
188
+ * @returns 预加载的窗口
189
+ */
134
190
  _createPreloadBW(options = {}) {
135
191
  return new Promise((resolve) => {
136
192
  const preload = this.preload;
137
- const url = this.preloadWebContentsUrl;
138
- if (this.preloadWebContentsUrl) {
193
+ const url = this.preloadWebContentsConfig?.url;
194
+ if (this.preloadWebContentsConfig?.url) {
195
+ const webPreferences = (options.webPreferences || {});
139
196
  const instance = new electron.BrowserWindow({
140
197
  show: false,
198
+ backgroundColor: '#ffffff',
141
199
  ...options,
142
200
  webPreferences: {
201
+ ...webPreferences,
143
202
  webviewTag: true,
144
203
  plugins: true,
145
204
  nodeIntegration: true,
146
205
  contextIsolation: false,
147
206
  backgroundThrottling: false,
148
207
  webSecurity: false,
149
- preload: preload,
150
- ...(options.webPreferences || {}),
208
+ preload: webPreferences.preload || preload,
151
209
  }
152
210
  });
153
211
  try {
@@ -164,31 +222,41 @@ class WindowsManager {
164
222
  log('error', '预加载 BW 设置 _id 失败', error);
165
223
  }
166
224
  // @ts-ignore
167
- log('log', '创建预BW: ', instance._id, this.preloadWebContentsUrl);
168
- instance.webContents.once('did-finish-load', () => {
169
- resolve(instance);
170
- });
171
- instance.webContents.once('did-fail-load', () => {
172
- resolve(instance);
173
- });
174
- instance.loadURL(url || 'about:blank');
225
+ log('log', '创建预BW: ', instance._id, this.preloadWebContentsConfig?.url);
226
+ // instance.webContents.once('did-finish-load', () => {
227
+ // resolve(instance as BWItem);
228
+ // });
229
+ // instance.webContents.once('did-fail-load', () => {
230
+ // resolve(instance as BWItem);
231
+ // });
232
+ instance.loadURL(url ? `${url}` : 'about:blank');
233
+ resolve(instance);
234
+ }
235
+ else {
236
+ resolve(null);
175
237
  }
176
238
  });
177
239
  }
178
- _createPreloadBV() {
240
+ /**
241
+ * 创建预加载的浏览器视图
242
+ * @returns 预加载的浏览器视图
243
+ */
244
+ _createPreloadBV(options = {}) {
179
245
  return new Promise((resolve) => {
180
246
  const preload = this.preload;
181
- const url = this.preloadWebContentsUrl;
182
- if (this.preloadWebContentsUrl) {
247
+ const url = this.preloadWebContentsConfig?.url;
248
+ if (this.preloadWebContentsConfig?.url) {
249
+ const webPreferences = (options.webPreferences || {});
183
250
  const instance = new electron.BrowserView({
184
251
  webPreferences: {
252
+ ...webPreferences,
185
253
  webviewTag: true,
186
254
  plugins: true,
187
255
  nodeIntegration: true,
188
256
  contextIsolation: false,
189
257
  // backgroundThrottling: false,
190
258
  webSecurity: false,
191
- preload: preload,
259
+ preload: webPreferences.preload || preload,
192
260
  }
193
261
  });
194
262
  try {
@@ -205,56 +273,123 @@ class WindowsManager {
205
273
  log('error', '预加载 BV 设置 _id 失败', error);
206
274
  }
207
275
  // @ts-ignore
208
- log('log', '创建预BV: ', instance._id, this.preloadWebContentsUrl);
209
- instance.webContents.once('did-finish-load', () => {
210
- resolve(instance);
211
- });
212
- instance.webContents.once('did-fail-load', () => {
213
- resolve(instance);
214
- });
276
+ log('log', '创建预BV: ', instance._id, this.preloadWebContentsConfig?.url);
277
+ // instance.webContents.once('did-finish-load', () => {
278
+ // resolve(instance as BVItem);
279
+ // });
280
+ // instance.webContents.once('did-fail-load', () => {
281
+ // resolve(instance as BVItem);
282
+ // });
215
283
  instance.webContents.loadURL(url || 'about:blank');
284
+ resolve(instance);
285
+ }
286
+ else {
287
+ resolve(null);
216
288
  }
217
289
  });
218
290
  }
219
291
  create(options) {
292
+ return new Promise((resolve, reject) => {
293
+ // 将创建请求添加到队列
294
+ this.createQueue.push({ options, resolve, reject });
295
+ // 如果当前没有在创建,则开始处理队列
296
+ if (!this.isCreating) {
297
+ this.processCreateQueue();
298
+ }
299
+ });
300
+ }
301
+ /**
302
+ * 处理创建队列
303
+ */
304
+ async processCreateQueue() {
305
+ if (this.isCreating || this.createQueue.length === 0) {
306
+ return;
307
+ }
308
+ this.isCreating = true;
309
+ while (this.createQueue.length > 0) {
310
+ const { options, resolve, reject } = this.createQueue.shift();
311
+ try {
312
+ const window = await this._createWindow(options);
313
+ resolve(window);
314
+ }
315
+ catch (error) {
316
+ log('error', 'create window failed:', error);
317
+ reject(error);
318
+ }
319
+ }
320
+ this.isCreating = false;
321
+ }
322
+ /**
323
+ * 实际的窗口创建逻辑
324
+ */
325
+ async _createWindow(options) {
220
326
  let window;
221
327
  const { usePreload = true, type = 'BW', name = 'anonymous', url, loadingView = { url: undefined }, errorView = { url: undefined }, browserWindow: browserWindowOptions, openDevTools = false, preventOriginClose = false, } = options;
222
328
  options.type = type;
223
329
  // 优先复用预创建实例
224
330
  let preloadWin = null;
225
- if (type === 'BW' && usePreload && this.preloadWebContentsUrl) {
331
+ if (type === 'BW' && usePreload && this.preloadWebContentsConfig?.url) {
226
332
  const bwOptions = browserWindowOptions || {};
227
- if (bwOptions.frame === false && bwOptions.titleBarStyle === 'hidden') {
228
- preloadWin = this.preloadedBW_FramelessWithButtons;
229
- this.preloadedBW_FramelessWithButtons = null;
230
- setTimeout(() => this._createPreloadBW({ frame: false, transparent: true, titleBarStyle: 'hidden' }), 0);
231
- }
232
- else if (bwOptions.frame === false && bwOptions.titleBarStyle === 'customButtonsOnHover') {
233
- preloadWin = this.preloadedBW_FramelessNoButtons;
234
- this.preloadedBW_FramelessNoButtons = null;
235
- setTimeout(() => this._createPreloadBW({ frame: false, transparent: true, titleBarStyle: 'customButtonsOnHover' }), 0);
333
+ if (bwOptions.frame === false) {
334
+ if (bwOptions.titleBarStyle === 'default' || !bwOptions.titleBarStyle) {
335
+ if (this.preloadWebContentsConfig.enableBW_FramelessNoButtons !== false && this.preloadedBW_FramelessNoButtons) {
336
+ preloadWin = this.preloadedBW_FramelessNoButtons;
337
+ this.preloadedBW_FramelessNoButtons = await this._createPreloadBW({
338
+ frame: false,
339
+ // transparent: true,
340
+ titleBarStyle: 'default',
341
+ webPreferences: {
342
+ preload: bwOptions?.webPreferences?.preload || this.preload,
343
+ }
344
+ });
345
+ }
346
+ }
347
+ else {
348
+ if (this.preloadWebContentsConfig.enableBW_FramelessWithButtons !== false && this.preloadedBW_FramelessWithButtons) {
349
+ preloadWin = this.preloadedBW_FramelessWithButtons;
350
+ this.preloadedBW_FramelessWithButtons = await this._createPreloadBW({
351
+ frame: false,
352
+ // transparent: true,
353
+ titleBarStyle: 'hidden',
354
+ webPreferences: {
355
+ preload: this.preload,
356
+ }
357
+ });
358
+ }
359
+ }
236
360
  }
237
361
  else {
238
- preloadWin = this.preloadedBW;
239
- this.preloadedBW = null;
240
- setTimeout(() => this._createPreloadBW({}), 0);
362
+ if (this.preloadWebContentsConfig.enableBW !== false && this.preloadedBW) {
363
+ preloadWin = this.preloadedBW;
364
+ this.preloadedBW = await this._createPreloadBW({
365
+ webPreferences: {
366
+ preload: bwOptions?.webPreferences?.preload || this.preload,
367
+ }
368
+ });
369
+ }
241
370
  }
242
371
  }
243
- if (type === 'BV' && usePreload && this.preloadWebContentsUrl) {
244
- preloadWin = this.preloadedBV;
245
- this.preloadedBV = null;
246
- setTimeout(() => this._createPreloadBV(), 0);
372
+ if (type === 'BV' && usePreload && this.preloadWebContentsConfig?.url) {
373
+ const bvOptions = browserWindowOptions || {};
374
+ if (this.preloadWebContentsConfig.enableBV !== false && this.preloadedBV) {
375
+ preloadWin = this.preloadedBV;
376
+ this.preloadedBV = await this._createPreloadBV({
377
+ webPreferences: {
378
+ preload: bvOptions?.webPreferences?.preload || this.preload,
379
+ }
380
+ });
381
+ }
247
382
  }
248
383
  if (preloadWin) {
249
384
  const win = preloadWin;
250
- log('log', `${name} 使用预加载窗口`, win._id);
385
+ log('log', `${name} 使用预加载窗口(${type})`, win._id);
251
386
  win._type = 'BW';
252
387
  win._name = options.name || 'anonymous';
253
388
  win._extraData = `${options?.extraData || ''}`;
254
389
  win._initUrl = `${options?.url || ''}`;
255
390
  // @ts-ignore
256
- win?.removeAllListeners && win?.removeAllListeners?.();
257
- win.webContents.removeAllListeners && win.webContents.removeAllListeners();
391
+ // win?.removeAllListeners && win?.removeAllListeners?.();
392
+ // win.webContents.removeAllListeners && win.webContents.removeAllListeners();
258
393
  if (type === 'BW') {
259
394
  // @ts-ignore
260
395
  this._applyBrowserWindowOptions(win, options);
@@ -262,27 +397,79 @@ class WindowsManager {
262
397
  if (type === 'BV') {
263
398
  this._applyBrowserViewOptions(win, options);
264
399
  }
400
+ if (typeof this.preloadWebContentsConfig?.customLoadURL === 'function') {
401
+ try {
402
+ if (type === 'BW') {
403
+ // @ts-ignore
404
+ const originLoadURL = win.loadURL;
405
+ // @ts-ignore
406
+ win.loadURL = async (url) => {
407
+ return new Promise(async (resolve, reject) => {
408
+ try {
409
+ console.error('customLoadURL win.loadURL');
410
+ // @ts-ignore
411
+ await this.preloadWebContentsConfig.customLoadURL(url || 'about:blank', (url) => originLoadURL.call(win, url), win.webContents);
412
+ try {
413
+ win.emit('ready-to-show');
414
+ }
415
+ catch (error) {
416
+ log('error', 'emit ready-to-show event failed:', error);
417
+ }
418
+ resolve(undefined);
419
+ }
420
+ catch (error) {
421
+ reject(error);
422
+ }
423
+ });
424
+ };
425
+ }
426
+ const originWebContentsLoadURL = win.webContents.loadURL;
427
+ // @ts-ignore
428
+ win.webContents.loadURL = async (url) => {
429
+ return new Promise(async (resolve, reject) => {
430
+ try {
431
+ console.error('customLoadURL win.webContents.loadURL');
432
+ // @ts-ignore
433
+ await this.preloadWebContentsConfig.customLoadURL(url || 'about:blank', (url) => originWebContentsLoadURL.call(win.webContents, url), win.webContents);
434
+ try {
435
+ win.webContents.emit('ready-to-show');
436
+ }
437
+ catch (error) {
438
+ log('error', 'emit ready-to-show event failed:', error);
439
+ }
440
+ resolve(undefined);
441
+ }
442
+ catch (error) {
443
+ reject(error);
444
+ }
445
+ });
446
+ };
447
+ }
448
+ catch (error) {
449
+ console.error('customLoadURL error', error);
450
+ }
451
+ }
265
452
  window = win;
266
453
  }
267
454
  try {
268
- try {
269
- loadingView.url = `${loadingView?.url ?? this.loadingViewUrl}`;
270
- lodash.merge(options, {
271
- loadingView,
272
- });
273
- }
274
- catch (error) {
275
- log('error', 'loadingView error:', loadingView, this.loadingViewUrl);
276
- }
277
- try {
278
- errorView.url = `${errorView?.url ?? this.errorViewUrl}`;
279
- lodash.merge(options, {
280
- errorView,
281
- });
282
- }
283
- catch (error) {
284
- log('error', 'errorView error:', errorView, this.errorViewUrl);
285
- }
455
+ loadingView.url = `${loadingView?.url ?? this.loadingViewUrl}`;
456
+ lodash.merge(options, {
457
+ loadingView,
458
+ });
459
+ }
460
+ catch (error) {
461
+ log('error', 'loadingView error:', loadingView, this.loadingViewUrl);
462
+ }
463
+ try {
464
+ errorView.url = `${errorView?.url ?? this.errorViewUrl}`;
465
+ lodash.merge(options, {
466
+ errorView,
467
+ });
468
+ }
469
+ catch (error) {
470
+ log('error', 'errorView error:', errorView, this.errorViewUrl);
471
+ }
472
+ try {
286
473
  let parentWin = undefined;
287
474
  if (typeof browserWindowOptions?.parent === 'number') {
288
475
  parentWin = electron.BrowserWindow.fromId(browserWindowOptions?.parent) || undefined;
@@ -336,6 +523,8 @@ class WindowsManager {
336
523
  log('error', 'enable: ', error);
337
524
  }
338
525
  }
526
+ // 停止加载
527
+ // window.webContents?.stop?.();
339
528
  // @ts-ignore
340
529
  try {
341
530
  window.id = Number(`${window.id || window.webContents.id}`);
@@ -364,7 +553,7 @@ class WindowsManager {
364
553
  if (errorView?.url) {
365
554
  if (type === 'BW') {
366
555
  const showErrorView = lodash.debounce(() => {
367
- const _url = window?.webContents?.getURL?.() || url;
556
+ const _url = window._initUrl;
368
557
  /**
369
558
  * 判断是否是错误视图
370
559
  */
@@ -378,16 +567,37 @@ class WindowsManager {
378
567
  sessionStorage.setItem(key, "${_url}");
379
568
  `);
380
569
  }
381
- }, 300);
570
+ }, 1000);
382
571
  // @ts-ignore
383
572
  window.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL, isMainFrame) => {
384
573
  if (isMainFrame) {
385
574
  showErrorView();
386
575
  }
387
576
  });
577
+ // 当开始加载时取消错误视图
388
578
  window.webContents.on('did-start-loading', () => {
389
579
  showErrorView.cancel();
390
580
  });
581
+ // 当导航开始时取消错误视图
582
+ window.webContents.on('did-start-navigation', () => {
583
+ showErrorView.cancel();
584
+ });
585
+ // 当页面重新加载时取消错误视图
586
+ window.webContents.on('did-navigate', () => {
587
+ showErrorView.cancel();
588
+ });
589
+ // 当页面完成加载时取消错误视图
590
+ window.webContents.on('did-finish-load', () => {
591
+ showErrorView.cancel();
592
+ });
593
+ // 当窗口关闭时取消错误视图
594
+ window.webContents.on('close', () => {
595
+ showErrorView.cancel();
596
+ });
597
+ // 当窗口销毁时取消错误视图
598
+ window.webContents.on('destroyed', () => {
599
+ showErrorView.cancel();
600
+ });
391
601
  }
392
602
  }
393
603
  window.webContents.on('did-attach-webview', (_event, webContents) => {
@@ -469,10 +679,6 @@ class WindowsManager {
469
679
  parentWin?.addBrowserView(window);
470
680
  log('log', 'create - addBrowserView');
471
681
  }
472
- // @ts-ignore
473
- window.loadURL ? window.loadURL(options.url) : window.webContents.loadURL(options.url);
474
- // @ts-ignore
475
- window.focus ? window.focus() : window.webContents.focus();
476
682
  this.windows.set(window.id || window._id || window.webContents.id, window);
477
683
  log('log', 'create', this.windows.keys());
478
684
  // 初始化值
@@ -565,6 +771,12 @@ class WindowsManager {
565
771
  log('error', 'focus', error);
566
772
  }
567
773
  }
774
+ if (options.url) {
775
+ // @ts-ignore
776
+ window.loadURL ? window.loadURL(options.url) : window.webContents.loadURL(options.url);
777
+ // @ts-ignore
778
+ window.focus ? window.focus() : window.webContents.focus();
779
+ }
568
780
  }
569
781
  catch (error) {
570
782
  log('error', 'create', error);
@@ -828,6 +1040,86 @@ class WindowsManager {
828
1040
  if (typeof browserWindowOptions.alwaysOnTop === 'boolean') {
829
1041
  win.setAlwaysOnTop(browserWindowOptions.alwaysOnTop);
830
1042
  }
1043
+ // 设置背景颜色
1044
+ if (typeof browserWindowOptions.backgroundColor === 'string') {
1045
+ win.setBackgroundColor(browserWindowOptions.backgroundColor);
1046
+ }
1047
+ // 居中
1048
+ if (browserWindowOptions?.center !== false) {
1049
+ win.center();
1050
+ }
1051
+ // 设置窗口移动
1052
+ if (typeof browserWindowOptions.movable === 'boolean') {
1053
+ win.setMovable(browserWindowOptions.movable);
1054
+ }
1055
+ // 设置窗口大小调整
1056
+ if (typeof browserWindowOptions.resizable === 'boolean') {
1057
+ win.setResizable(browserWindowOptions.resizable);
1058
+ }
1059
+ // 设置全屏模式
1060
+ if (typeof browserWindowOptions.fullscreenable === 'boolean') {
1061
+ win.setFullScreenable(browserWindowOptions.fullscreenable);
1062
+ }
1063
+ // 设置窗口阴影
1064
+ if (typeof browserWindowOptions.hasShadow === 'boolean') {
1065
+ win.setHasShadow(browserWindowOptions.hasShadow);
1066
+ }
1067
+ // 设置窗口最小尺寸
1068
+ if (typeof browserWindowOptions.minWidth === 'number' && typeof browserWindowOptions.minHeight === 'number') {
1069
+ win.setMinimumSize(browserWindowOptions.minWidth, browserWindowOptions.minHeight);
1070
+ }
1071
+ // 设置窗口最大尺寸
1072
+ if (typeof browserWindowOptions.maxWidth === 'number' && typeof browserWindowOptions.maxHeight === 'number') {
1073
+ win.setMaximumSize(browserWindowOptions.maxWidth, browserWindowOptions.maxHeight);
1074
+ }
1075
+ // 设置窗口位置
1076
+ if (typeof browserWindowOptions.x === 'number' && typeof browserWindowOptions.y === 'number') {
1077
+ win.setPosition(browserWindowOptions.x, browserWindowOptions.y);
1078
+ }
1079
+ // 设置窗口标题
1080
+ if (typeof browserWindowOptions.title === 'string') {
1081
+ win.setTitle(browserWindowOptions.title);
1082
+ }
1083
+ // 设置窗口图标
1084
+ if (typeof browserWindowOptions.icon === 'string') {
1085
+ win.setIcon(browserWindowOptions.icon);
1086
+ }
1087
+ // 设置窗口菜单栏可见性
1088
+ if (typeof browserWindowOptions.autoHideMenuBar === 'boolean') {
1089
+ win.setAutoHideMenuBar(browserWindowOptions.autoHideMenuBar);
1090
+ }
1091
+ // 设置窗口最小化按钮
1092
+ if (browserWindowOptions.minimizable === false) {
1093
+ win.setMinimizable(false);
1094
+ }
1095
+ // 设置窗口最大化按钮
1096
+ if (browserWindowOptions.maximizable === false) {
1097
+ win.setMaximizable(false);
1098
+ }
1099
+ // 设置窗口关闭按钮
1100
+ if (browserWindowOptions.closable === false) {
1101
+ win.setClosable(false);
1102
+ }
1103
+ // 设置窗口焦点
1104
+ if (browserWindowOptions.focusable === false) {
1105
+ win.setFocusable(false);
1106
+ }
1107
+ // 设置窗口全屏
1108
+ if (browserWindowOptions.fullscreen === true) {
1109
+ win.setFullScreen(true);
1110
+ }
1111
+ // 设置窗口背景材质
1112
+ if (typeof browserWindowOptions.vibrancy === 'string') {
1113
+ win.setVibrancy(browserWindowOptions.vibrancy);
1114
+ }
1115
+ // 设置窗口透明度
1116
+ if (typeof browserWindowOptions.opacity === 'number') {
1117
+ win.setOpacity(browserWindowOptions.opacity);
1118
+ }
1119
+ // 设置窗口显示状态
1120
+ if (browserWindowOptions.show === false) {
1121
+ win.hide();
1122
+ }
831
1123
  // 可继续扩展其他动态属性
832
1124
  }
833
1125
  _applyBrowserViewOptions(view, options) {
@@ -843,12 +1135,26 @@ class WindowsManager {
843
1135
  if (typeof browserWindowOptions.width === 'number' && typeof browserWindowOptions.height === 'number') {
844
1136
  view.setBounds({ x: 0, y: 0, width: browserWindowOptions.width, height: browserWindowOptions.height });
845
1137
  }
1138
+ // 设置视图位置
1139
+ if (typeof browserWindowOptions.x === 'number' && typeof browserWindowOptions.y === 'number') {
1140
+ const bounds = view.getBounds();
1141
+ view.setBounds({
1142
+ x: browserWindowOptions.x,
1143
+ y: browserWindowOptions.y,
1144
+ width: bounds.width,
1145
+ height: bounds.height
1146
+ });
1147
+ }
1148
+ // 设置视图背景颜色
1149
+ if (typeof browserWindowOptions.backgroundColor === 'string') {
1150
+ view.setBackgroundColor(browserWindowOptions.backgroundColor);
1151
+ }
846
1152
  // 可继续扩展其他动态属性
847
1153
  }
848
1154
  // 生成一个bv 做为预加载资源窗口,加载完成后销毁
849
1155
  async createPreloadWebContents(url) {
850
1156
  return new Promise(async (resolve, reject) => {
851
- let bv = this.create({
1157
+ let bv = await this.create({
852
1158
  type: 'BV',
853
1159
  url,
854
1160
  name: `preload-web-contents-${md5(url)}`,
@@ -871,7 +1177,7 @@ class WindowsManager {
871
1177
  // @ts-ignore
872
1178
  global['__ELECTRON_WINDOWS_MANAGER__'] = undefined;
873
1179
  exports.isInitialized = false;
874
- const initialize = (preload, loadingViewUrl, errorViewUrl, preloadWebContentsUrl, webviewDomainWhiteList) => {
1180
+ const initialize = (preload, loadingViewUrl, errorViewUrl, preloadWebContentsConfig, webviewDomainWhiteList) => {
875
1181
  // @ts-ignore
876
1182
  if (exports.isInitialized && global['__ELECTRON_WINDOWS_MANAGER__']) {
877
1183
  // @ts-ignore
@@ -879,7 +1185,7 @@ const initialize = (preload, loadingViewUrl, errorViewUrl, preloadWebContentsUrl
879
1185
  }
880
1186
  exports.isInitialized = true;
881
1187
  // @ts-ignore
882
- const wm = global['__ELECTRON_WINDOWS_MANAGER__'] = new WindowsManager(preload, loadingViewUrl, errorViewUrl, preloadWebContentsUrl, webviewDomainWhiteList);
1188
+ const wm = global['__ELECTRON_WINDOWS_MANAGER__'] = new WindowsManager(preload, loadingViewUrl, errorViewUrl, preloadWebContentsConfig, webviewDomainWhiteList);
883
1189
  eIpc.mainIPC.handleRenderer('__ELECTRON_WINDOW_MANAGER_IPC_CHANNEL__', async (data) => {
884
1190
  if (data?.type === 'create') {
885
1191
  const opt = data;
@@ -903,7 +1209,7 @@ const initialize = (preload, loadingViewUrl, errorViewUrl, preloadWebContentsUrl
903
1209
  winInitUrl: `${findWin?._initUrl || ''}`,
904
1210
  };
905
1211
  }
906
- const res = wm.create(opt.data);
1212
+ const res = await wm.create(opt.data);
907
1213
  return {
908
1214
  winId: Number(`${res.id || res._id || -1}`),
909
1215
  winName: `${res?._name || ''}`,
@@ -1039,9 +1345,9 @@ const initialize = (preload, loadingViewUrl, errorViewUrl, preloadWebContentsUrl
1039
1345
  return undefined;
1040
1346
  }
1041
1347
  // 是否开启预加载窗口
1042
- if (data?.type === 'setPreloadWebContentsUrl') {
1348
+ if (data?.type === 'setPreloadWebContentsConfig') {
1043
1349
  const opt = data;
1044
- wm.setPreloadWebContentsUrl(opt.data);
1350
+ wm.setPreloadWebContentsConfig(opt.data);
1045
1351
  }
1046
1352
  if (data?.type === 'createPreloadWebContents') {
1047
1353
  const opt = data;