@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/esm/main/index.js CHANGED
@@ -56,30 +56,43 @@ class WindowsManager {
56
56
  * - 不带点的(如 example.com)只匹配主域名。
57
57
  * - 'localhost'、'127.0.0.1'、'::1' 以及局域网 IP(如 192.168.x.x、10.x.x.x、172.16.x.x~172.31.x.x)都视为本地白名单。
58
58
  */
59
- constructor(preload, loadingViewUrl, errorViewUrl, preloadWebContentsUrl, webviewDomainWhiteList) {
59
+ constructor(preload, loadingViewUrl, errorViewUrl, preloadWebContentsConfig, webviewDomainWhiteList) {
60
+ // 预加载的窗口
60
61
  this.preloadedBW = null;
62
+ // 预加载的窗口(无边框,有按钮)
61
63
  this.preloadedBW_FramelessWithButtons = null;
64
+ // 预加载的窗口(无边框,无按钮)
62
65
  this.preloadedBW_FramelessNoButtons = null;
66
+ // 预加载的浏览器视图
63
67
  this.preloadedBV = null;
64
68
  this.preloading = false;
65
69
  this.webviewDomainWhiteList = [];
70
+ // 创建队列相关属性
71
+ this.createQueue = [];
72
+ this.isCreating = false;
66
73
  this.preload = preload;
67
74
  this.windows = new Map();
68
75
  this.loadingViewUrl = `${loadingViewUrl ?? ''}`;
69
76
  this.errorViewUrl = `${errorViewUrl ?? ''}`;
70
- this.preloadWebContentsUrl = `${preloadWebContentsUrl ?? ''}`;
77
+ this.preloadWebContentsConfig = preloadWebContentsConfig;
71
78
  this.webviewDomainWhiteList = webviewDomainWhiteList || [];
72
- log('log', 'preloadWebContentsUrl: ', this.preloadWebContentsUrl);
73
- if (this.preloadWebContentsUrl) {
74
- app.on('ready', () => {
75
- this._preloadInstances();
79
+ log('log', 'preloadWebContentsConfig: ', this.preloadWebContentsConfig);
80
+ if (this.preloadWebContentsConfig) {
81
+ app.whenReady().then(() => {
82
+ if (this.preloadWebContentsConfig) {
83
+ this.setPreloadWebContentsConfig(this.preloadWebContentsConfig);
84
+ }
76
85
  });
77
86
  }
78
87
  }
79
- setPreloadWebContentsUrl(preloadWebContentsUrl) {
88
+ /**
89
+ * 设置预加载的webContents配置
90
+ * @param preloadWebContentsConfig 预加载的webContents配置
91
+ */
92
+ setPreloadWebContentsConfig(preloadWebContentsConfig) {
80
93
  try {
81
- this.preloadWebContentsUrl = preloadWebContentsUrl;
82
- if (this.preloadWebContentsUrl) {
94
+ this.preloadWebContentsConfig = preloadWebContentsConfig;
95
+ if (this.preloadWebContentsConfig) {
83
96
  this._preloadInstances();
84
97
  }
85
98
  else {
@@ -90,27 +103,65 @@ class WindowsManager {
90
103
  }
91
104
  }
92
105
  catch (error) {
93
- log('error', 'setPreloadWebContentsUrl error:', error);
106
+ log('error', 'setPreloadWebContentsConfig error:', error);
94
107
  }
95
108
  }
109
+ /**
110
+ * 预加载实例
111
+ */
96
112
  async _preloadInstances() {
97
113
  if (this.preloading)
98
114
  return;
99
115
  this.preloading = true;
100
116
  try {
101
- if (this.preloadWebContentsUrl) {
102
- this.preloadedBW = this.preloadedBW || await this._createPreloadBW({});
103
- this.preloadedBW_FramelessWithButtons = this.preloadedBW_FramelessWithButtons || await this._createPreloadBW({
104
- frame: false,
105
- transparent: true,
106
- titleBarStyle: 'hidden',
107
- });
108
- this.preloadedBW_FramelessNoButtons = this.preloadedBW_FramelessNoButtons || await this._createPreloadBW({
109
- frame: false,
110
- transparent: true,
111
- titleBarStyle: 'customButtonsOnHover',
112
- });
113
- this.preloadedBV = this.preloadedBV || await this._createPreloadBV();
117
+ if (this.preloadWebContentsConfig) {
118
+ log('log', 'preloadWebContentsConfig: ', this.preloadWebContentsConfig);
119
+ // 根据配置决定是否预加载普通窗口
120
+ if (this.preloadWebContentsConfig.enableBW !== false) {
121
+ if (!this.preloadedBW) {
122
+ this._createPreloadBW({}).then(i => {
123
+ this.preloadedBW = i;
124
+ log('log', 'init preloadedBW: ', !!this.preloadedBW);
125
+ });
126
+ }
127
+ }
128
+ // 根据配置决定是否预加载无边框有按钮的窗口
129
+ if (this.preloadWebContentsConfig.enableBW_FramelessWithButtons !== false) {
130
+ if (!this.preloadedBW_FramelessWithButtons) {
131
+ this._createPreloadBW({
132
+ frame: false,
133
+ // transparent: true,
134
+ autoHideMenuBar: true,
135
+ titleBarStyle: 'hidden',
136
+ }).then(i => {
137
+ this.preloadedBW_FramelessWithButtons = i;
138
+ log('log', 'init preloadedBW_FramelessWithButtons: ', !!this.preloadedBW_FramelessWithButtons);
139
+ });
140
+ }
141
+ }
142
+ // 根据配置决定是否预加载无边框无按钮的窗口
143
+ if (this.preloadWebContentsConfig.enableBW_FramelessNoButtons !== false) {
144
+ if (!this.preloadedBW_FramelessNoButtons) {
145
+ this._createPreloadBW({
146
+ frame: false,
147
+ // transparent: true,
148
+ autoHideMenuBar: true,
149
+ titleBarStyle: 'default',
150
+ }).then(i => {
151
+ this.preloadedBW_FramelessNoButtons = i;
152
+ log('log', 'init preloadedBW_FramelessNoButtons: ', !!this.preloadedBW_FramelessNoButtons);
153
+ });
154
+ }
155
+ }
156
+ // 根据配置决定是否预加载浏览器视图
157
+ if (this.preloadWebContentsConfig.enableBV !== false) {
158
+ if (!this.preloadedBV) {
159
+ this._createPreloadBV().then(i => {
160
+ this.preloadedBV = i;
161
+ log('log', 'init preloadedBV: ', !!this.preloadedBV);
162
+ });
163
+ }
164
+ }
114
165
  }
115
166
  }
116
167
  catch (e) {
@@ -118,23 +169,31 @@ class WindowsManager {
118
169
  }
119
170
  this.preloading = false;
120
171
  }
172
+ /**
173
+ * 创建预加载的窗口
174
+ * @param options 窗口选项
175
+ * @returns 预加载的窗口
176
+ */
121
177
  _createPreloadBW(options = {}) {
122
178
  return new Promise((resolve) => {
123
179
  const preload = this.preload;
124
- const url = this.preloadWebContentsUrl;
125
- if (this.preloadWebContentsUrl) {
180
+ const url = this.preloadWebContentsConfig?.url;
181
+ if (this.preloadWebContentsConfig?.url) {
182
+ const webPreferences = (options.webPreferences || {});
126
183
  const instance = new BrowserWindow({
184
+ useContentSize: true,
127
185
  show: false,
186
+ backgroundColor: '#ffffff',
128
187
  ...options,
129
188
  webPreferences: {
189
+ ...webPreferences,
130
190
  webviewTag: true,
131
191
  plugins: true,
132
192
  nodeIntegration: true,
133
193
  contextIsolation: false,
134
194
  backgroundThrottling: false,
135
195
  webSecurity: false,
136
- preload: preload,
137
- ...(options.webPreferences || {}),
196
+ preload: webPreferences.preload || preload,
138
197
  }
139
198
  });
140
199
  try {
@@ -151,31 +210,41 @@ class WindowsManager {
151
210
  log('error', '预加载 BW 设置 _id 失败', error);
152
211
  }
153
212
  // @ts-ignore
154
- log('log', '创建预BW: ', instance._id, this.preloadWebContentsUrl);
155
- instance.webContents.once('did-finish-load', () => {
156
- resolve(instance);
157
- });
158
- instance.webContents.once('did-fail-load', () => {
159
- resolve(instance);
160
- });
161
- instance.loadURL(url || 'about:blank');
213
+ log('log', '创建预BW: ', instance._id, this.preloadWebContentsConfig?.url);
214
+ // instance.webContents.once('did-finish-load', () => {
215
+ // resolve(instance as BWItem);
216
+ // });
217
+ // instance.webContents.once('did-fail-load', () => {
218
+ // resolve(instance as BWItem);
219
+ // });
220
+ instance.loadURL(url ? `${url}` : 'about:blank');
221
+ resolve(instance);
222
+ }
223
+ else {
224
+ resolve(null);
162
225
  }
163
226
  });
164
227
  }
165
- _createPreloadBV() {
228
+ /**
229
+ * 创建预加载的浏览器视图
230
+ * @returns 预加载的浏览器视图
231
+ */
232
+ _createPreloadBV(options = {}) {
166
233
  return new Promise((resolve) => {
167
234
  const preload = this.preload;
168
- const url = this.preloadWebContentsUrl;
169
- if (this.preloadWebContentsUrl) {
235
+ const url = this.preloadWebContentsConfig?.url;
236
+ if (this.preloadWebContentsConfig?.url) {
237
+ const webPreferences = (options.webPreferences || {});
170
238
  const instance = new BrowserView({
171
239
  webPreferences: {
240
+ ...webPreferences,
172
241
  webviewTag: true,
173
242
  plugins: true,
174
243
  nodeIntegration: true,
175
244
  contextIsolation: false,
176
245
  // backgroundThrottling: false,
177
246
  webSecurity: false,
178
- preload: preload,
247
+ preload: webPreferences.preload || preload,
179
248
  }
180
249
  });
181
250
  try {
@@ -192,56 +261,123 @@ class WindowsManager {
192
261
  log('error', '预加载 BV 设置 _id 失败', error);
193
262
  }
194
263
  // @ts-ignore
195
- log('log', '创建预BV: ', instance._id, this.preloadWebContentsUrl);
196
- instance.webContents.once('did-finish-load', () => {
197
- resolve(instance);
198
- });
199
- instance.webContents.once('did-fail-load', () => {
200
- resolve(instance);
201
- });
264
+ log('log', '创建预BV: ', instance._id, this.preloadWebContentsConfig?.url);
265
+ // instance.webContents.once('did-finish-load', () => {
266
+ // resolve(instance as BVItem);
267
+ // });
268
+ // instance.webContents.once('did-fail-load', () => {
269
+ // resolve(instance as BVItem);
270
+ // });
202
271
  instance.webContents.loadURL(url || 'about:blank');
272
+ resolve(instance);
273
+ }
274
+ else {
275
+ resolve(null);
203
276
  }
204
277
  });
205
278
  }
206
279
  create(options) {
280
+ return new Promise((resolve, reject) => {
281
+ // 将创建请求添加到队列
282
+ this.createQueue.push({ options, resolve, reject });
283
+ // 如果当前没有在创建,则开始处理队列
284
+ if (!this.isCreating) {
285
+ this.processCreateQueue();
286
+ }
287
+ });
288
+ }
289
+ /**
290
+ * 处理创建队列
291
+ */
292
+ async processCreateQueue() {
293
+ if (this.isCreating || this.createQueue.length === 0) {
294
+ return;
295
+ }
296
+ this.isCreating = true;
297
+ while (this.createQueue.length > 0) {
298
+ const { options, resolve, reject } = this.createQueue.shift();
299
+ try {
300
+ const window = await this._createWindow(options);
301
+ resolve(window);
302
+ }
303
+ catch (error) {
304
+ log('error', 'create window failed:', error);
305
+ reject(error);
306
+ }
307
+ }
308
+ this.isCreating = false;
309
+ }
310
+ /**
311
+ * 实际的窗口创建逻辑
312
+ */
313
+ async _createWindow(options) {
207
314
  let window;
208
315
  const { usePreload = true, type = 'BW', name = 'anonymous', url, loadingView = { url: undefined }, errorView = { url: undefined }, browserWindow: browserWindowOptions, openDevTools = false, preventOriginClose = false, } = options;
209
316
  options.type = type;
210
317
  // 优先复用预创建实例
211
318
  let preloadWin = null;
212
- if (type === 'BW' && usePreload && this.preloadWebContentsUrl) {
319
+ if (type === 'BW' && usePreload && this.preloadWebContentsConfig?.url) {
213
320
  const bwOptions = browserWindowOptions || {};
214
- if (bwOptions.frame === false && bwOptions.titleBarStyle === 'hidden') {
215
- preloadWin = this.preloadedBW_FramelessWithButtons;
216
- this.preloadedBW_FramelessWithButtons = null;
217
- setTimeout(() => this._createPreloadBW({ frame: false, transparent: true, titleBarStyle: 'hidden' }), 0);
218
- }
219
- else if (bwOptions.frame === false && bwOptions.titleBarStyle === 'customButtonsOnHover') {
220
- preloadWin = this.preloadedBW_FramelessNoButtons;
221
- this.preloadedBW_FramelessNoButtons = null;
222
- setTimeout(() => this._createPreloadBW({ frame: false, transparent: true, titleBarStyle: 'customButtonsOnHover' }), 0);
321
+ if (bwOptions.frame === false) {
322
+ if (bwOptions.titleBarStyle === 'default' || !bwOptions.titleBarStyle) {
323
+ if (this.preloadWebContentsConfig.enableBW_FramelessNoButtons !== false && this.preloadedBW_FramelessNoButtons) {
324
+ preloadWin = this.preloadedBW_FramelessNoButtons;
325
+ this.preloadedBW_FramelessNoButtons = await this._createPreloadBW({
326
+ frame: false,
327
+ // transparent: true,
328
+ titleBarStyle: 'default',
329
+ webPreferences: {
330
+ preload: bwOptions?.webPreferences?.preload || this.preload,
331
+ }
332
+ });
333
+ }
334
+ }
335
+ else {
336
+ if (this.preloadWebContentsConfig.enableBW_FramelessWithButtons !== false && this.preloadedBW_FramelessWithButtons) {
337
+ preloadWin = this.preloadedBW_FramelessWithButtons;
338
+ this.preloadedBW_FramelessWithButtons = await this._createPreloadBW({
339
+ frame: false,
340
+ // transparent: true,
341
+ titleBarStyle: 'hidden',
342
+ webPreferences: {
343
+ preload: this.preload,
344
+ }
345
+ });
346
+ }
347
+ }
223
348
  }
224
349
  else {
225
- preloadWin = this.preloadedBW;
226
- this.preloadedBW = null;
227
- setTimeout(() => this._createPreloadBW({}), 0);
350
+ if (this.preloadWebContentsConfig.enableBW !== false && this.preloadedBW) {
351
+ preloadWin = this.preloadedBW;
352
+ this.preloadedBW = await this._createPreloadBW({
353
+ webPreferences: {
354
+ preload: bwOptions?.webPreferences?.preload || this.preload,
355
+ }
356
+ });
357
+ }
228
358
  }
229
359
  }
230
- if (type === 'BV' && usePreload && this.preloadWebContentsUrl) {
231
- preloadWin = this.preloadedBV;
232
- this.preloadedBV = null;
233
- setTimeout(() => this._createPreloadBV(), 0);
360
+ if (type === 'BV' && usePreload && this.preloadWebContentsConfig?.url) {
361
+ const bvOptions = browserWindowOptions || {};
362
+ if (this.preloadWebContentsConfig.enableBV !== false && this.preloadedBV) {
363
+ preloadWin = this.preloadedBV;
364
+ this.preloadedBV = await this._createPreloadBV({
365
+ webPreferences: {
366
+ preload: bvOptions?.webPreferences?.preload || this.preload,
367
+ }
368
+ });
369
+ }
234
370
  }
235
371
  if (preloadWin) {
236
372
  const win = preloadWin;
237
- log('log', `${name} 使用预加载窗口`, win._id);
373
+ log('log', `${name} 使用预加载窗口(${type})`, win._id);
238
374
  win._type = 'BW';
239
375
  win._name = options.name || 'anonymous';
240
376
  win._extraData = `${options?.extraData || ''}`;
241
377
  win._initUrl = `${options?.url || ''}`;
242
378
  // @ts-ignore
243
- win?.removeAllListeners && win?.removeAllListeners?.();
244
- win.webContents.removeAllListeners && win.webContents.removeAllListeners();
379
+ // win?.removeAllListeners && win?.removeAllListeners?.();
380
+ // win.webContents.removeAllListeners && win.webContents.removeAllListeners();
245
381
  if (type === 'BW') {
246
382
  // @ts-ignore
247
383
  this._applyBrowserWindowOptions(win, options);
@@ -249,27 +385,79 @@ class WindowsManager {
249
385
  if (type === 'BV') {
250
386
  this._applyBrowserViewOptions(win, options);
251
387
  }
388
+ if (typeof this.preloadWebContentsConfig?.customLoadURL === 'function') {
389
+ try {
390
+ if (type === 'BW') {
391
+ // @ts-ignore
392
+ const originLoadURL = win.loadURL;
393
+ // @ts-ignore
394
+ win.loadURL = async (url) => {
395
+ return new Promise(async (resolve, reject) => {
396
+ try {
397
+ console.error('customLoadURL win.loadURL');
398
+ // @ts-ignore
399
+ await this.preloadWebContentsConfig.customLoadURL(url || 'about:blank', (url) => originLoadURL.call(win, url), win.webContents);
400
+ try {
401
+ win.emit('ready-to-show');
402
+ }
403
+ catch (error) {
404
+ log('error', 'emit ready-to-show event failed:', error);
405
+ }
406
+ resolve(undefined);
407
+ }
408
+ catch (error) {
409
+ reject(error);
410
+ }
411
+ });
412
+ };
413
+ }
414
+ const originWebContentsLoadURL = win.webContents.loadURL;
415
+ // @ts-ignore
416
+ win.webContents.loadURL = async (url) => {
417
+ return new Promise(async (resolve, reject) => {
418
+ try {
419
+ console.error('customLoadURL win.webContents.loadURL');
420
+ // @ts-ignore
421
+ await this.preloadWebContentsConfig.customLoadURL(url || 'about:blank', (url) => originWebContentsLoadURL.call(win.webContents, url), win.webContents);
422
+ try {
423
+ win.webContents.emit('ready-to-show');
424
+ }
425
+ catch (error) {
426
+ log('error', 'emit ready-to-show event failed:', error);
427
+ }
428
+ resolve(undefined);
429
+ }
430
+ catch (error) {
431
+ reject(error);
432
+ }
433
+ });
434
+ };
435
+ }
436
+ catch (error) {
437
+ console.error('customLoadURL error', error);
438
+ }
439
+ }
252
440
  window = win;
253
441
  }
254
442
  try {
255
- try {
256
- loadingView.url = `${loadingView?.url ?? this.loadingViewUrl}`;
257
- lodash.merge(options, {
258
- loadingView,
259
- });
260
- }
261
- catch (error) {
262
- log('error', 'loadingView error:', loadingView, this.loadingViewUrl);
263
- }
264
- try {
265
- errorView.url = `${errorView?.url ?? this.errorViewUrl}`;
266
- lodash.merge(options, {
267
- errorView,
268
- });
269
- }
270
- catch (error) {
271
- log('error', 'errorView error:', errorView, this.errorViewUrl);
272
- }
443
+ loadingView.url = `${loadingView?.url ?? this.loadingViewUrl}`;
444
+ lodash.merge(options, {
445
+ loadingView,
446
+ });
447
+ }
448
+ catch (error) {
449
+ log('error', 'loadingView error:', loadingView, this.loadingViewUrl);
450
+ }
451
+ try {
452
+ errorView.url = `${errorView?.url ?? this.errorViewUrl}`;
453
+ lodash.merge(options, {
454
+ errorView,
455
+ });
456
+ }
457
+ catch (error) {
458
+ log('error', 'errorView error:', errorView, this.errorViewUrl);
459
+ }
460
+ try {
273
461
  let parentWin = undefined;
274
462
  if (typeof browserWindowOptions?.parent === 'number') {
275
463
  parentWin = BrowserWindow.fromId(browserWindowOptions?.parent) || undefined;
@@ -323,6 +511,8 @@ class WindowsManager {
323
511
  log('error', 'enable: ', error);
324
512
  }
325
513
  }
514
+ // 停止加载
515
+ // window.webContents?.stop?.();
326
516
  // @ts-ignore
327
517
  try {
328
518
  window.id = Number(`${window.id || window.webContents.id}`);
@@ -351,7 +541,7 @@ class WindowsManager {
351
541
  if (errorView?.url) {
352
542
  if (type === 'BW') {
353
543
  const showErrorView = lodash.debounce(() => {
354
- const _url = window?.webContents?.getURL?.() || url;
544
+ const _url = window._initUrl;
355
545
  /**
356
546
  * 判断是否是错误视图
357
547
  */
@@ -365,16 +555,37 @@ class WindowsManager {
365
555
  sessionStorage.setItem(key, "${_url}");
366
556
  `);
367
557
  }
368
- }, 300);
558
+ }, 1000);
369
559
  // @ts-ignore
370
560
  window.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL, isMainFrame) => {
371
561
  if (isMainFrame) {
372
562
  showErrorView();
373
563
  }
374
564
  });
565
+ // 当开始加载时取消错误视图
375
566
  window.webContents.on('did-start-loading', () => {
376
567
  showErrorView.cancel();
377
568
  });
569
+ // 当导航开始时取消错误视图
570
+ window.webContents.on('did-start-navigation', () => {
571
+ showErrorView.cancel();
572
+ });
573
+ // 当页面重新加载时取消错误视图
574
+ window.webContents.on('did-navigate', () => {
575
+ showErrorView.cancel();
576
+ });
577
+ // 当页面完成加载时取消错误视图
578
+ window.webContents.on('did-finish-load', () => {
579
+ showErrorView.cancel();
580
+ });
581
+ // 当窗口关闭时取消错误视图
582
+ window.webContents.on('close', () => {
583
+ showErrorView.cancel();
584
+ });
585
+ // 当窗口销毁时取消错误视图
586
+ window.webContents.on('destroyed', () => {
587
+ showErrorView.cancel();
588
+ });
378
589
  }
379
590
  }
380
591
  window.webContents.on('did-attach-webview', (_event, webContents) => {
@@ -456,10 +667,6 @@ class WindowsManager {
456
667
  parentWin?.addBrowserView(window);
457
668
  log('log', 'create - addBrowserView');
458
669
  }
459
- // @ts-ignore
460
- window.loadURL ? window.loadURL(options.url) : window.webContents.loadURL(options.url);
461
- // @ts-ignore
462
- window.focus ? window.focus() : window.webContents.focus();
463
670
  this.windows.set(window.id || window._id || window.webContents.id, window);
464
671
  log('log', 'create', this.windows.keys());
465
672
  // 初始化值
@@ -552,6 +759,12 @@ class WindowsManager {
552
759
  log('error', 'focus', error);
553
760
  }
554
761
  }
762
+ if (options.url) {
763
+ // @ts-ignore
764
+ window.loadURL ? window.loadURL(options.url) : window.webContents.loadURL(options.url);
765
+ // @ts-ignore
766
+ window.focus ? window.focus() : window.webContents.focus();
767
+ }
555
768
  }
556
769
  catch (error) {
557
770
  log('error', 'create', error);
@@ -815,6 +1028,86 @@ class WindowsManager {
815
1028
  if (typeof browserWindowOptions.alwaysOnTop === 'boolean') {
816
1029
  win.setAlwaysOnTop(browserWindowOptions.alwaysOnTop);
817
1030
  }
1031
+ // 设置背景颜色
1032
+ if (typeof browserWindowOptions.backgroundColor === 'string') {
1033
+ win.setBackgroundColor(browserWindowOptions.backgroundColor);
1034
+ }
1035
+ // 居中
1036
+ if (browserWindowOptions?.center !== false) {
1037
+ win.center();
1038
+ }
1039
+ // 设置窗口移动
1040
+ if (typeof browserWindowOptions.movable === 'boolean') {
1041
+ win.setMovable(browserWindowOptions.movable);
1042
+ }
1043
+ // 设置窗口大小调整
1044
+ if (typeof browserWindowOptions.resizable === 'boolean') {
1045
+ win.setResizable(browserWindowOptions.resizable);
1046
+ }
1047
+ // 设置全屏模式
1048
+ if (typeof browserWindowOptions.fullscreenable === 'boolean') {
1049
+ win.setFullScreenable(browserWindowOptions.fullscreenable);
1050
+ }
1051
+ // 设置窗口阴影
1052
+ if (typeof browserWindowOptions.hasShadow === 'boolean') {
1053
+ win.setHasShadow(browserWindowOptions.hasShadow);
1054
+ }
1055
+ // 设置窗口最小尺寸
1056
+ if (typeof browserWindowOptions.minWidth === 'number' && typeof browserWindowOptions.minHeight === 'number') {
1057
+ win.setMinimumSize(browserWindowOptions.minWidth, browserWindowOptions.minHeight);
1058
+ }
1059
+ // 设置窗口最大尺寸
1060
+ if (typeof browserWindowOptions.maxWidth === 'number' && typeof browserWindowOptions.maxHeight === 'number') {
1061
+ win.setMaximumSize(browserWindowOptions.maxWidth, browserWindowOptions.maxHeight);
1062
+ }
1063
+ // 设置窗口位置
1064
+ if (typeof browserWindowOptions.x === 'number' && typeof browserWindowOptions.y === 'number') {
1065
+ win.setPosition(browserWindowOptions.x, browserWindowOptions.y);
1066
+ }
1067
+ // 设置窗口标题
1068
+ if (typeof browserWindowOptions.title === 'string') {
1069
+ win.setTitle(browserWindowOptions.title);
1070
+ }
1071
+ // 设置窗口图标
1072
+ if (typeof browserWindowOptions.icon === 'string') {
1073
+ win.setIcon(browserWindowOptions.icon);
1074
+ }
1075
+ // 设置窗口菜单栏可见性
1076
+ if (typeof browserWindowOptions.autoHideMenuBar === 'boolean') {
1077
+ win.setAutoHideMenuBar(browserWindowOptions.autoHideMenuBar);
1078
+ }
1079
+ // 设置窗口最小化按钮
1080
+ if (browserWindowOptions.minimizable === false) {
1081
+ win.setMinimizable(false);
1082
+ }
1083
+ // 设置窗口最大化按钮
1084
+ if (browserWindowOptions.maximizable === false) {
1085
+ win.setMaximizable(false);
1086
+ }
1087
+ // 设置窗口关闭按钮
1088
+ if (browserWindowOptions.closable === false) {
1089
+ win.setClosable(false);
1090
+ }
1091
+ // 设置窗口焦点
1092
+ if (browserWindowOptions.focusable === false) {
1093
+ win.setFocusable(false);
1094
+ }
1095
+ // 设置窗口全屏
1096
+ if (browserWindowOptions.fullscreen === true) {
1097
+ win.setFullScreen(true);
1098
+ }
1099
+ // 设置窗口背景材质
1100
+ if (typeof browserWindowOptions.vibrancy === 'string') {
1101
+ win.setVibrancy(browserWindowOptions.vibrancy);
1102
+ }
1103
+ // 设置窗口透明度
1104
+ if (typeof browserWindowOptions.opacity === 'number') {
1105
+ win.setOpacity(browserWindowOptions.opacity);
1106
+ }
1107
+ // 设置窗口显示状态
1108
+ if (browserWindowOptions.show === false) {
1109
+ win.hide();
1110
+ }
818
1111
  // 可继续扩展其他动态属性
819
1112
  }
820
1113
  _applyBrowserViewOptions(view, options) {
@@ -830,12 +1123,26 @@ class WindowsManager {
830
1123
  if (typeof browserWindowOptions.width === 'number' && typeof browserWindowOptions.height === 'number') {
831
1124
  view.setBounds({ x: 0, y: 0, width: browserWindowOptions.width, height: browserWindowOptions.height });
832
1125
  }
1126
+ // 设置视图位置
1127
+ if (typeof browserWindowOptions.x === 'number' && typeof browserWindowOptions.y === 'number') {
1128
+ const bounds = view.getBounds();
1129
+ view.setBounds({
1130
+ x: browserWindowOptions.x,
1131
+ y: browserWindowOptions.y,
1132
+ width: bounds.width,
1133
+ height: bounds.height
1134
+ });
1135
+ }
1136
+ // 设置视图背景颜色
1137
+ if (typeof browserWindowOptions.backgroundColor === 'string') {
1138
+ view.setBackgroundColor(browserWindowOptions.backgroundColor);
1139
+ }
833
1140
  // 可继续扩展其他动态属性
834
1141
  }
835
1142
  // 生成一个bv 做为预加载资源窗口,加载完成后销毁
836
1143
  async createPreloadWebContents(url) {
837
1144
  return new Promise(async (resolve, reject) => {
838
- let bv = this.create({
1145
+ let bv = await this.create({
839
1146
  type: 'BV',
840
1147
  url,
841
1148
  name: `preload-web-contents-${md5(url)}`,
@@ -858,7 +1165,7 @@ class WindowsManager {
858
1165
  // @ts-ignore
859
1166
  global['__ELECTRON_WINDOWS_MANAGER__'] = undefined;
860
1167
  let isInitialized = false;
861
- const initialize = (preload, loadingViewUrl, errorViewUrl, preloadWebContentsUrl, webviewDomainWhiteList) => {
1168
+ const initialize = (preload, loadingViewUrl, errorViewUrl, preloadWebContentsConfig, webviewDomainWhiteList) => {
862
1169
  // @ts-ignore
863
1170
  if (isInitialized && global['__ELECTRON_WINDOWS_MANAGER__']) {
864
1171
  // @ts-ignore
@@ -866,7 +1173,7 @@ const initialize = (preload, loadingViewUrl, errorViewUrl, preloadWebContentsUrl
866
1173
  }
867
1174
  isInitialized = true;
868
1175
  // @ts-ignore
869
- const wm = global['__ELECTRON_WINDOWS_MANAGER__'] = new WindowsManager(preload, loadingViewUrl, errorViewUrl, preloadWebContentsUrl, webviewDomainWhiteList);
1176
+ const wm = global['__ELECTRON_WINDOWS_MANAGER__'] = new WindowsManager(preload, loadingViewUrl, errorViewUrl, preloadWebContentsConfig, webviewDomainWhiteList);
870
1177
  eIpc.mainIPC.handleRenderer('__ELECTRON_WINDOW_MANAGER_IPC_CHANNEL__', async (data) => {
871
1178
  if (data?.type === 'create') {
872
1179
  const opt = data;
@@ -890,7 +1197,7 @@ const initialize = (preload, loadingViewUrl, errorViewUrl, preloadWebContentsUrl
890
1197
  winInitUrl: `${findWin?._initUrl || ''}`,
891
1198
  };
892
1199
  }
893
- const res = wm.create(opt.data);
1200
+ const res = await wm.create(opt.data);
894
1201
  return {
895
1202
  winId: Number(`${res.id || res._id || -1}`),
896
1203
  winName: `${res?._name || ''}`,
@@ -1026,9 +1333,9 @@ const initialize = (preload, loadingViewUrl, errorViewUrl, preloadWebContentsUrl
1026
1333
  return undefined;
1027
1334
  }
1028
1335
  // 是否开启预加载窗口
1029
- if (data?.type === 'setPreloadWebContentsUrl') {
1336
+ if (data?.type === 'setPreloadWebContentsConfig') {
1030
1337
  const opt = data;
1031
- wm.setPreloadWebContentsUrl(opt.data);
1338
+ wm.setPreloadWebContentsConfig(opt.data);
1032
1339
  }
1033
1340
  if (data?.type === 'createPreloadWebContents') {
1034
1341
  const opt = data;