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