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

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