Electron開發(fā): Electron 窗口開發(fā)詳解及常見問題解答

本文主要講解Electron 窗口的 API 和一些在開發(fā)之中遇到的問題哑姚。

官方文檔 雖然比較全面祭饭,但是要想開發(fā)一個(gè)商用級別的桌面應(yīng)用必須對整個(gè) Electron API 有較深的了解,才能應(yīng)對各種需求蜻懦。

1. 創(chuàng)建窗口

通過BrowserWindow甜癞,來 創(chuàng)建 或者 管理 新的瀏覽器窗口,每個(gè)瀏覽器窗口都有一個(gè)進(jìn)程來管理宛乃。

1.1. 簡單創(chuàng)建窗口

const { BrowserWindow } = require('electron');
const win = new BrowserWindow();
win.loadURL('https://github.com');

效果如下:


image.png

1.1.2. 優(yōu)化

問題electronBrowserWindow 模塊在創(chuàng)建時(shí)悠咱,如果沒有配置 show:false,在創(chuàng)建之時(shí)就會(huì)顯示出來征炼,且默認(rèn)的背景是白色析既;然后窗口請求 HTML,會(huì)出現(xiàn)視覺閃爍谆奥。

解決

const { BrowserWindow } = require('electron');
const win = new BrowserWindow({ show:false });

win.loadURL('https://github.com');

win.on('ready-to-show',()=>{
    win.show();
})

兩者對比有很大的區(qū)別

image.png

1.2. 管理窗口

所謂的管理窗口眼坏,相當(dāng)于主進(jìn)程可以干預(yù)窗口多少。

  • 窗口的路由跳轉(zhuǎn)
  • 窗口打開新的窗口
  • 窗口大小酸些、位置等
  • 窗口的顯示
  • 窗口類型(無邊框窗口宰译、父子窗口)
  • 窗口內(nèi) JavaScriptnode 權(quán)限,預(yù)加載腳本等
  • ....

這些個(gè)方法都存在于BrowserWindow模塊中魄懂。

1.2.1. 管理應(yīng)用創(chuàng)建的窗口

BrowserWindow模塊在創(chuàng)建窗口時(shí)沿侈,會(huì)返回 窗口實(shí)例,這些 窗口實(shí)例 上有許多功能方法市栗,我們利用這些方法缀拭,管理控制這個(gè)窗口。

在這里使用Map對象來存儲(chǔ)這些 窗口實(shí)例填帽。

const BrowserWindowsMap = new Map<number, BrowserWindow>()
let mainWindowId: number;

const browserWindows = new BrowserWindow({ show:false })
browserWindows.loadURL('https://github.com')
browserWindows.once('ready-to-show', () => {
  browserWindows.show()
})
BrowserWindowsMap.set(browserWindow.id, browserWindow)
mainWindowId = browserWindow.id  // 記錄當(dāng)前窗口為主窗口

窗口被關(guān)閉蛛淋,得把Map中的實(shí)例刪除。

browserWindow.on('closed', () => {
  BrowserWindowsMap?.delete(browserWindowID)
})

1.2.2. 管理用戶創(chuàng)建的窗口

主進(jìn)程可以控制窗口許多行為篡腌,這些行為會(huì)在后續(xù)文章一一列舉褐荷;以下以主進(jìn)程控制窗口建立新窗口的行為為例。

使用**new-window**監(jiān)聽新窗口創(chuàng)建

// 創(chuàng)建窗口監(jiān)聽
browserWindow.webContents.on('new-window', (event, url, frameName, disposition) => {
  /** @params {string} disposition
  *  new-window : window.open調(diào)用
  *  background-tab: command+click
  *  foreground-tab: 右鍵點(diǎn)擊新標(biāo)簽打開或點(diǎn)擊a標(biāo)簽target _blank打開
  * /
})

注:關(guān)于disposition字段的解釋嘹悼,移步 electron文檔诚卸、electron源碼葵第、chrome 源碼

擴(kuò)展**new-window**

經(jīng)過實(shí)驗(yàn)绘迁,并不是所有新窗口的建立合溺, new-window 都能捕捉到的。

以下方式打開的窗口可以被**new-window**事件捕捉到

window.open('https://github.com')
<a  target='__blank'>鏈接</a>

渲染進(jìn)程中使用 **BrowserWindow** 創(chuàng)建新窗口缀台,不會(huì)被 **new-window**事件捕捉到

const { BrowserWindow } = require('electron').remote
const win = new BrowserWindow()
win.loadURL('https://github.com')

*渲染進(jìn)程訪問 * *remote* *棠赛,主進(jìn)程需配置 *enableRemoteModule:true

使用這種方式同樣可以打開一個(gè)新的窗口,但是主進(jìn)程的 new-window 捕捉不到膛腐。

應(yīng)用**new-window**

new-window 控制著窗口新窗口的創(chuàng)建睛约,我們利用這點(diǎn),可以做到很多事情哲身;比如鏈接校驗(yàn)辩涝、瀏覽器打開鏈接等等。默認(rèn)瀏覽器打開鏈接代碼如下:

import { shell } from 'electron'
function openExternal(url: string) {
  const HTTP_REGEXP = /^https?:\/\//
  // 非http協(xié)議不打開勘天,防止出現(xiàn)自定義協(xié)議等導(dǎo)致的安全問題
  if (!HTTP_REGEXP) {
    return false
  }
  try {
    await shell.openExternal(url, options)
    return true
  } catch (error) {
    console.error('open external error: ', error)
    return false
  }
}
// 創(chuàng)建窗口監(jiān)聽
browserWindow.webContents.on('new-window', (event, url, frameName, disposition) => {
  if (disposition === 'foreground-tab') {
      // 阻止鼠標(biāo)點(diǎn)擊鏈接
      event.preventDefault()
      openExternal(url)
  }
})

關(guān)于 *shell* 模塊怔揩,可以查看官網(wǎng) https://www.electronjs.org/docs/api/shell

1.3. 關(guān)閉窗口

**close** 事件和 **closed** 事件

close事件在窗口將要關(guān)閉時(shí)之前觸發(fā),但是在 DOMbeforeunloadunload 事件之前觸發(fā)脯丝。

// 窗口注冊close事件
win.on('close',(event)=>{
    event.preventDefault()  // 阻止窗口關(guān)閉
})

closed 事件在窗口關(guān)閉后出觸發(fā)商膊,但是此時(shí)的窗口已經(jīng)被關(guān)閉了,無法通過 event.preventDefault() 來阻止窗口關(guān)閉宠进。

win.on('closed', handler)

主進(jìn)程能夠關(guān)閉窗口的 API 有很多晕拆,但都有各自的利弊。

1.3.1. win.close()

關(guān)于這個(gè) API 的利弊

  1. 如果當(dāng)前窗口實(shí)例注冊并阻止close事件材蹬,將不會(huì)關(guān)閉頁面实幕,而且也會(huì) 阻止計(jì)算機(jī)關(guān)閉(必須手動(dòng)強(qiáng)制退出);
  2. 關(guān)閉頁面的服務(wù)堤器,如websocket昆庇,下次打開窗口,窗口中的頁面會(huì) 重新渲染吼旧;
  3. 通過這個(gè)API觸發(fā)的close事件在 unloadbeforeunload之前觸發(fā)凰锡,通過這點(diǎn)可以實(shí)現(xiàn) 關(guān)閉時(shí)觸發(fā)彈窗
image.png
  1. 會(huì)被closed事件捕捉到圈暗。

1.3.2. win.destroy()

  1. 強(qiáng)制退出掂为,無視 close 事件(即:無法通過 event.preventDefault() 來阻止);
  2. 關(guān)閉頁面员串,以及頁面內(nèi)的服務(wù)勇哗,下次打開窗口,窗口中的頁面會(huì)重新渲染寸齐;
  3. 會(huì)被 closed 事件捕捉到欲诺。

1.3.3. win.hide()

這個(gè)隱藏窗口抄谐。

  1. 隱藏窗口,會(huì)觸發(fā) hideblur 事件扰法,同樣也是可以通過 event.preventDefault() 來阻止
  2. 只是隱藏窗口蛹含,通過 win.show(),可以將窗口顯現(xiàn)塞颁,并且會(huì)保持原來的窗口浦箱,里面的服務(wù)也不會(huì)掛斷

2. 主窗口隱藏和恢復(fù)

2.1. 主窗口

2.1.1. 為什么需要 主窗口?

一個(gè)應(yīng)用存在著許多的窗口,需要一個(gè)窗口作為 主窗口祠锣,如果該窗口關(guān)閉酷窥,則意味著整個(gè)應(yīng)用被關(guān)閉。

場景:在應(yīng)用只有一個(gè)頁面的時(shí)伴网,用戶點(diǎn)擊關(guān)閉按鈕蓬推,不想讓整個(gè)應(yīng)用關(guān)閉,而是隱藏澡腾;

例如:其他的APP沸伏,像微信,QQ等桌面端蛋铆。

利用上文中提到的關(guān)閉窗口的 API ,我們實(shí)現(xiàn)一個(gè)主窗口的隱藏和恢復(fù)馋评。

改造一下 close 事件

let mainWindowId: number // 用于標(biāo)記主窗口id

const browserWindow = new BrowserWindow()

// 記錄下主窗口id
if (!mainWindowId) {
  mainWindowId = browserWindow.id
}

browserWindow.on('close', event => {
  // 如果關(guān)閉的是主窗口,阻止
  if (browserWindow.id === mainWindowId) {
    event.preventDefault()
    browserWindow.hide()
  }
})

2.1.2. 恢復(fù)主窗口顯示

能隱藏刺啦,就能恢復(fù)留特。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
支付 ¥9.99 繼續(xù)閱讀
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市玛瘸,隨后出現(xiàn)的幾起案子蜕青,更是在濱河造成了極大的恐慌,老刑警劉巖糊渊,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件右核,死亡現(xiàn)場離奇詭異,居然都是意外死亡渺绒,警方通過查閱死者的電腦和手機(jī)贺喝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宗兼,“玉大人躏鱼,你說我怎么就攤上這事∫笊埽” “怎么了染苛?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長主到。 經(jīng)常有香客問我茶行,道長丧没,這世上最難降的妖魔是什么兔乞? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任狂魔,我火速辦了婚禮缸剪,結(jié)果婚禮上擂找,老公的妹妹穿的比我還像新娘手报。我一直安慰自己黄锤,他們只是感情好骗爆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著度陆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪献幔。 梳的紋絲不亂的頭發(fā)上懂傀,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機(jī)與錄音蜡感,去河邊找鬼蹬蚁。 笑死,一個(gè)胖子當(dāng)著我的面吹牛郑兴,可吹牛的內(nèi)容都是我干的犀斋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼情连,長吁一口氣:“原來是場噩夢啊……” “哼叽粹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起却舀,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤虫几,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后挽拔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辆脸,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年螃诅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了啡氢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡术裸,死狀恐怖倘是,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情穗椅,我是刑警寧澤辨绊,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站匹表,受9級特大地震影響门坷,放射性物質(zhì)發(fā)生泄漏宣鄙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一默蚌、第九天 我趴在偏房一處隱蔽的房頂上張望冻晤。 院中可真熱鬧,春花似錦绸吸、人聲如沸鼻弧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽攘轩。三九已至,卻和暖如春码俩,著一層夾襖步出監(jiān)牢的瞬間度帮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工稿存, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留笨篷,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓瓣履,卻偏偏與公主長得像率翅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子袖迎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容