日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

第二章 你第首個Electron應(yīng)用 | Electron in Action(中譯)

 看見就非常 2020-05-25

本章主要內(nèi)容

  • 構(gòu)建并啟動Electron應(yīng)用

  • 生成package.json,配置成Electron應(yīng)用

  • 在你的項目中包含預(yù)先構(gòu)建Electron版本

  • 配置package.json以啟動主進(jìn)程

  • 從主進(jìn)程生成渲染進(jìn)程

  • 利用Electron限制寬松的優(yōu)點構(gòu)建通常在瀏覽器無法構(gòu)建的功能

  • 使用Electron的內(nèi)置模塊來回避一些常見的問題

在第一章中,我們從高的層次上,討論了什么是Electron。說到底這本書叫做《Electron實戰(zhàn)》,對吧?在本章中,我們通過從頭開始設(shè)置和構(gòu)建一個簡單的應(yīng)用程序來管理書簽列表,從而學(xué)習(xí)Electron的基本知識。該應(yīng)用程序?qū)⒗弥挥性诂F(xiàn)代的瀏覽器中才能使用的特性。

在上一章的高層次討論中,我提到了Electron是一個類似于Node的運行時。這仍然是正確的,但是我想回顧下這一點。Electron不是一個框架——它不提供任何框架,也沒有關(guān)于如何構(gòu)造應(yīng)用程序或命名文件的嚴(yán)格規(guī)則,這些選擇都留給了我們這些開發(fā)者。好的一面是,它也不強(qiáng)制執(zhí)行任何約定,而且在入手之前,我們不需要多少概念上的樣板信息去學(xué)習(xí)。

 

構(gòu)建書簽列表應(yīng)用程序

 

讓我們從構(gòu)建一個簡單而又有些幼稚的Electron應(yīng)用程序開始,來加強(qiáng)我們已經(jīng)介紹過的所有內(nèi)容的理解。我們的應(yīng)用程序接受url。當(dāng)用戶提供URL時,我們獲取URL引用的頁面的標(biāo)題,并將其保存在應(yīng)用程序的localStorage中。最后,顯示應(yīng)用程序中的所有鏈接。您可以在GitHub上找到本章的完整源代碼(https://github.com/electron-in-action/bookmarker)。

  在此過程中,我們將指出構(gòu)建Electron應(yīng)用程序的一些優(yōu)點,例如,可以繞過對服務(wù)器的需求,使用最前沿的web api,這些web api并不廣泛支持所有瀏覽器,因為這些APIs是在現(xiàn)代版本的Chromium中實現(xiàn)。圖2.1是我們在本章構(gòu)建的應(yīng)用程序的效果圖。

圖2.1 我們在本章中構(gòu)建的應(yīng)用程序效果圖

 

  當(dāng)用戶希望將網(wǎng)站URL保存并添加到輸入字段下面的列表中時,應(yīng)用程序向網(wǎng)站發(fā)送一個請求來獲取標(biāo)記。成功接收到標(biāo)記后,應(yīng)用程序獲取網(wǎng)站的標(biāo)題,并將標(biāo)題和URL添加到網(wǎng)站列表中,該列表存儲在瀏覽器的localStorage中。當(dāng)應(yīng)用程序啟動時,它從localStorage讀取并恢復(fù)列表。我們添加了一個帶有命令的按鈕來清除localStorage,以防出現(xiàn)錯誤。因為這個簡單的應(yīng)用程序旨在幫助您熟悉Electron,所以我們不會執(zhí)行高級操作,比如從列表中刪除單個網(wǎng)站。

 

搭建Electron應(yīng)用

  1. npm init 生成package.json

  2. 搭建Electron目錄框架

 

應(yīng)用程序結(jié)構(gòu)的定義取決于您的團(tuán)隊或個人處理應(yīng)用程序的方式。許多開發(fā)人員采用的方法略有不同。觀察學(xué)習(xí)一些更成熟的電子應(yīng)用程序,我們可以辨別出共同的模式,并在本書中決定如何處理我們的應(yīng)用程序。

出于我們的目的,為了讓本書文件結(jié)構(gòu)達(dá)成一致。做出一下規(guī)定,我們有一個應(yīng)用程序目錄,其中存儲了所有的應(yīng)用程序代碼。我們還有一個package.json將存儲依賴項列表、關(guān)于應(yīng)用程序的元數(shù)據(jù)和腳本,并聲明Electron應(yīng)該在何處查找主進(jìn)程。在安裝了依賴項之后,最終會得到一個由Electron為我們創(chuàng)建的node_modules目錄,但是我們不會在初始設(shè)置中包含它

就文件而言,讓我們從應(yīng)用程序中的兩個文件開始:main.jsrenderer.js。它們是帶有標(biāo)識的文件名,因此我們可以跟蹤這兩種類型的進(jìn)程。我們在本書中構(gòu)建的所有應(yīng)用程序的開始大致遵循圖2.2中所示的目錄結(jié)構(gòu)。(如果你在運行macOS,你可以通過安裝brew install tree使用tree命令。)

圖2.2 我們第一個Electron應(yīng)用的文件結(jié)構(gòu)樹

 

創(chuàng)建一個名為“bookmarker”的目錄,并進(jìn)入此目錄。您可以通過從命令行工具運行以下兩個命令來快速創(chuàng)建這個結(jié)構(gòu)。當(dāng)你使用npm init之后,你會生成一個package.json文件。

mkdir app
touch app/main.js app/renderer.js app/style.css app/index.html

 

Electron本身不需要這種結(jié)構(gòu),但它受到了其他Electron應(yīng)用程序建立的一些最佳實踐的啟發(fā)。Atom將所有應(yīng)用程序代碼保存在一個app目錄中,將所有樣式表和其他資產(chǎn)(如圖像)保存在一個靜態(tài)目錄中。LevelUI在頂層有一個index.js和一個client.js,并將所有依賴文件保存在src目錄中,樣式表保存在styles目錄中。Yoda將所有文件(包括加載應(yīng)用程序其余部分的文件)保存在src目錄中。app、src和lib是存放應(yīng)用程序大部分代碼的文件夾的常用名稱,style、static和assets是存放應(yīng)用程序中使用的靜態(tài)資產(chǎn)的目錄的常用名稱。

 

package.json

package.json清單用于許多甚至說大多數(shù)Node項目。此清單包含有關(guān)項目的重要信息。它列出了元數(shù)據(jù),比如作者的姓名以及他們的電子郵件地址、項目是在哪個許可下發(fā)布的、項目的git存儲庫的位置以及文件問題的位置。它還為一些常見的任務(wù)定義了腳本,比如運行測試套件或者與我們的需求相關(guān)的構(gòu)建應(yīng)用程序。package.json文件還列出了用于運行和開發(fā)應(yīng)用程序的所有依賴項。

理論上,您可能有一個沒有package.json的Node項目。但是,當(dāng)加載或構(gòu)建應(yīng)用程序時,Electron依賴于該文件及其主要屬性來確定從何處開始。

npm是Node附帶的包管理器,它提供了一個有用的工具幫助生成package.json。在前面創(chuàng)建的“bookmarker”目錄中運行npm init。如果您將提示符留空,npm將冒號后面括號中的內(nèi)容作為默認(rèn)內(nèi)容。您的內(nèi)容應(yīng)該類似于圖2.3,當(dāng)然,除了作者的名字之外。

在package.json中,值得注意的是main條目。這里,你可以看到我將它設(shè)置為"./app/main.js"。基于我們?nèi)绾卧O(shè)置應(yīng)用程序。你可以指向任何你想要的文件。我們要用的主文件恰好叫做main.js。但是它可以被命名為任何東西(例如,sandwich.js、index.js、app.js)。

圖2.3 npm init 提供一系列提示并設(shè)置一個package.json文件

 

下載和安裝Electron在我們的項目

我們已經(jīng)建立了應(yīng)用程序的基本結(jié)構(gòu),但是卻找不到Electron。從源代碼編譯Electron需要一段時間,而且可能很乏味。因此我們根據(jù)每個平臺(macOS、Windows和Linux)以及兩種體系結(jié)構(gòu)(32位和64位)預(yù)先構(gòu)建了electronic版本。我們通過npm安裝Electron。

下載和安裝電子很容易。在您運行npm init之前,在你的項目目錄中運行以下命令:

npm install electron --save-dev

此命令將在你的項目node_modules目錄下下載并安裝Electron(如果您還沒有目錄,它還會創(chuàng)建目錄)。--save-dev標(biāo)志將其添加到package.json的依賴項列表中。這意味著如果有人下載了這個項目并運行npm install,他們將默認(rèn)獲得Electron。

 

漫談electron-prebuilt

假如您了解Electron的歷史,您可能會看到博客文章、文檔,甚至本書的早期版本,其中提到的是electron-prebuilt,而不是electron。在過去,前者是為操作系統(tǒng)安裝預(yù)編譯版Electron的首選方法。后者是新的首選方法。從2017年初開始,不再支持electron-prebuilt。

 

npm還允許您定義在package.json中運行公共腳本的快捷方式。當(dāng)您運行package.json定義的腳本時。npm自動添加node_modules到這個路徑。這意味著它將默認(rèn)使用本地安裝的Electron版本。讓我們向package.json添加一個start腳本。

列表2.1  向package.json添加一個啟動腳本

{                                                        +
"name": "bookmarker",                                    |當(dāng)我們運行npm start
"version": "1.0.0",                                      |npm將會運行什么腳本
"description": "Our very first Electron application",    |
"main": "./app/main.js",                                 |
"scripts": {                                             |
"start": "electron .",                            <------+
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Steve Kinney",
"license": "ISC",
"dependencies": {
"electron": "^2.0.4"
}
}
?

現(xiàn)在,當(dāng)我們運行npm start時,npm使用我們本地安裝的版本Electron去啟動Electron應(yīng)用程序。你會注意到似乎沒有什么事情發(fā)生。在你的終端中,它實際運行以下程式碼:

>bookmarker@1.0.0  start /Users/stevekinney/Projects/bookmarker
>electron .

您還將在dock或任務(wù)欄中看到一個新應(yīng)用程序(我們剛剛設(shè)置的Electron應(yīng)用程序),如圖2.4所示。它被簡稱為“Electron”,并使用Electron的默認(rèn)應(yīng)用程序圖標(biāo)。在后面的章節(jié)中,我們將看到如何定制這些屬性,但是目前默認(rèn)值已經(jīng)足夠好了。我們所有的代碼文件都是完全空白的。因此,這個應(yīng)用程序還有很多操作需要去做,但是它確實存在并正確啟動。我們認(rèn)為這是一場暫時的勝利。在windows上關(guān)閉應(yīng)用程序的所有窗口或選擇退出應(yīng)用程序菜單終止進(jìn)程?;蛘?,您可以在Windows命令提示符或終端中按Control-C退出應(yīng)用程序。按下Command-Period將終止macOS上的進(jìn)程。

圖2.4 dock上的應(yīng)用程序就是我們剛建立的電子應(yīng)用

處理主進(jìn)程

現(xiàn)在我們有了一個Electron應(yīng)用,如果我們真的能讓它做點什么,那就太好了。如果你還記得第一章,我們從可以創(chuàng)建一個或多個渲染器進(jìn)程的主進(jìn)程開始。我們首先通過編寫main.js代碼,邁出我們應(yīng)用程序的第一步。

要處理Electron,我們需要導(dǎo)入electron庫。Electron附帶了許多有用的模塊,我們在本書中使用了這些模塊。第一個—也可以說是最重要的——是app模塊。

列表2.2 添加一個基本的主進(jìn)程: ./app/main.js

?
const {app} = require('electron');     +
app.on('ready', () => {            <---+ 在應(yīng)用程序完全
console.log('Hello from Electron');   + 啟后立即調(diào)用
});
?

app是一個處理應(yīng)用程序生命周期和配置的模塊。我們可以使用它退出、隱藏和顯示應(yīng)用程序,以及獲取和設(shè)置應(yīng)用程序的屬性。app模塊還可以運行事件-包括before-quit, window -all-closed,

browser-window-blur, 和browser-window-focus-當(dāng)應(yīng)用程序進(jìn)入不同狀態(tài)時。

在應(yīng)用程序完全啟動并準(zhǔn)備就緒之前,我們無法處理它。幸運的是,app觸發(fā)了一個ready事件。這意味著在做任何事之前,我們需要耐心等待并監(jiān)聽?wèi)?yīng)用程序啟動ready事件。在前面的代碼中,我們在控制臺打印日志,這是一件無需Electron就可以輕松完成的事情,但是這段代碼強(qiáng)調(diào)了如何偵聽ready事件。

 

創(chuàng)建渲染器進(jìn)程

我們的主進(jìn)程與其他Node進(jìn)程非常相似。它可以訪問Node的所有內(nèi)置庫以及由Electron提供的一組特殊模塊,我們將在本書中對此進(jìn)行探討。但是,與任何其他Node進(jìn)程一樣,我們的主進(jìn)程沒有DOM(文檔對象模型),也不能呈現(xiàn)UI。主進(jìn)程負(fù)責(zé)與操作系統(tǒng)交互,管理狀態(tài),并與應(yīng)用程序中的所有其他流程進(jìn)行協(xié)調(diào)。它不負(fù)責(zé)呈現(xiàn)HTML和CSS。這就是渲染器進(jìn)程的工作。參與整個Electron主要功能之一是為Node進(jìn)程創(chuàng)建一個GUI。

主進(jìn)程可以使用BrowserWindow創(chuàng)建多個渲染器進(jìn)程。每個BrowserWindow都是一個單獨的、惟一的渲染器器進(jìn)程,包括一個DOM,訪問Chromium web APIs,以及Node內(nèi)置模塊。訪問BrowserWindow模塊的方式與訪問app模塊的方式相同。

 

列表2.3 引用BrowserWindow模塊: ./app/main.js

const {app, BrowserWindow} = require('electron');

 

您可能已經(jīng)注意到BrowserWindow模塊以大寫字母開頭。根據(jù)標(biāo)準(zhǔn)JavaScript約定,這通常意味著我們用new關(guān)鍵字將其調(diào)用為構(gòu)造函數(shù)。我們可以使用這個構(gòu)造函數(shù)創(chuàng)建盡可能多的渲染器進(jìn)程,只要我們喜歡,或者我們的計算機(jī)可以處理。當(dāng)應(yīng)用程序就緒時,我們創(chuàng)建一個BrowserWindow實例。讓我們按照以下方式更新代碼。

 

列表2.4 生成一個BrowserWindow: ./app/main.js

                                                    +
const {app, BrowserWindow} = require('electron');   |在我們的應(yīng)用程序中創(chuàng)建一個
let mainWindow = null;                         <----+window對象的全局引用
app.on('ready', () => {                  +          +
console.log('Hello from Electron.');    |當(dāng)應(yīng)用程序準(zhǔn)備好時,
mainWindow = new BrowserWindow();  <----+創(chuàng)建一個瀏覽器窗口
});                                      +并將其分配給全局變量
?

我們在ready事件監(jiān)聽器外聲明了mainWindow。JavaScript使用函數(shù)作用域。如果我們在事件監(jiān)聽器中聲明mainWindow, mainWindow將進(jìn)行垃圾回收,因為分配給ready事件的函數(shù)已經(jīng)運行完畢。如果被垃圾回收,我們的窗戶就會神秘地消失。如果我們運行這段代碼,我們會在屏幕中央看到一個不起眼的小窗口,如圖2.5所示。

一個沒有加載HTML文檔的空BrowserWindow

 

這是一扇窗口,并什么好看的。下一步是將HTML頁面加載到我們創(chuàng)建的BrowserWindow實例中。所有BrowserWindow實例都有一個web content屬性,該屬性具有幾個有用的特性,比如將HTML文件加載到渲染器進(jìn)程的窗口中、從主進(jìn)程向渲染器進(jìn)程發(fā)送消息、將頁面打印為PDF或打印機(jī)等等?,F(xiàn)在,我們最關(guān)心的是將內(nèi)容加載到我們剛剛創(chuàng)建的那個無聊的窗口中。

  我們需要加載一個HTML頁面,因此在您項目的app目錄中創(chuàng)建index.html。讓我們將以下內(nèi)容添加到HTML頁面,使其成為一個有效的文檔。

 

列表2.5 創(chuàng)建index.html: ./app/index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy"
content="
default-src 'self';
script-src 'self' 'unsafe-inline';
connect-src *
"
>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Bookmarker</title>
</head>
<body>
<h1>Hello from Electron</h1>
</body>
</html>

這很簡單,但它完成了工作,并為構(gòu)建打下了良好的基礎(chǔ)。我們將以下代碼添加到app/main.js中,以告訴渲染器進(jìn)程在我們之前創(chuàng)建的窗口中加載這個HTML文檔。

列表2.6 將HTML文檔加載到主窗口: ./app/main.js

我們使用file://protocol_dirname變量,該變量在Node中全局可用。_dirname是Node進(jìn)程正在執(zhí)行的目錄的完整路徑。在我的例子中,_dirname擴(kuò)展為/Users/stevekinney/Projects/bookmarker/app。

現(xiàn)在,我們可以使用npm start啟動應(yīng)用程序,并觀察它加載新的HTML文件。如果一切順利,您應(yīng)該會看到類似于圖2.6的內(nèi)容。

 

從渲染進(jìn)程加載代碼

從渲染器進(jìn)程加載的HTML文件中,我們可以像在傳統(tǒng)的基于瀏覽器的web應(yīng)用程序中一樣加載可能需要的任何其他文件-即<script><link>標(biāo)簽。

Electron與我們習(xí)慣的瀏覽器不同之處在于我們可以訪問所有Node——甚至是我們通常認(rèn)為的“客戶端”。這意味著,我們可以使用require甚至Node-only對象和變量,比如_dirnameprocess模塊。同時,我們還有所有可用的瀏覽器APIs。只能在客戶端的工作和只能在服務(wù)端做的工作的分工開始消失不見。

圖2.6 一個帶有簡單HTML文檔的瀏覽器窗口

讓我們來看看實際情況。在傳統(tǒng)的瀏覽器環(huán)境中_dirname不可用,在Node中documentalert是不可用的。但在Electron,我們可以無縫地將它們結(jié)合在一起。讓我們在頁面上添加一個按鈕。

列表2.7 添加一個按鈕到HTML文檔: ./app/index. html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF+8">
<meta http+equiv="Content+Security+Policy" content=" default+src 'self'; script+src 'self' 'unsafe+inline';connect+src *">
<meta name="viewport" content="width=device+width,initial+scale=1">
<title>Bookmarker</title>
</head>
<body>
<h1>Hello from Electron</h1>
<p>
<button class="alert">Current Directory</button>     <---+
</p>                                                     |這是我們
</body>                                                 |的新按鈕
</html>                                                 +
?

 

現(xiàn)在,我們已經(jīng)有了按鈕,讓我們添加一個事件監(jiān)聽器,它將提醒我們運行應(yīng)用程序的當(dāng)前目錄。

<script>
 const button = document.querySelector('.alert');
 button.addEventListener('click', () =^ {
 alert(__dirname);             <------+單擊按鈕時,
});                                  |使用瀏覽器警告顯示
</script>                             |Node全局變量
                                      +
?

alert()僅在瀏覽器中可用。_dirname僅在Node中可用。當(dāng)我們點擊按鈕時,我們被處理成Node和Chromium在一起工作,甜美和諧,如圖2.7所示。

圖2.7 在渲染器進(jìn)程的上下文中,BrowserWindow執(zhí)行JavaScript。

 

在渲染器進(jìn)程中引用文件

在HTML文件中編寫代碼顯然有效,但是不難想象,我們的代碼量可能會增長到這種方法不再可行的地步。我們可以添加帶有src屬性的腳本標(biāo)記來引用其他文件,但是這很快就會變得很麻煩。

這就是web開發(fā)變得棘手的地方。雖然模塊被添加到ECMAScript規(guī)范中,目前沒有瀏覽器具有模塊系統(tǒng)的工作實現(xiàn)。在客戶端上,我們可以考慮使用一些構(gòu)建工具,如Browserify (http://)或模塊bundler、webpack,也可以使用任務(wù)運行器,如GulpGrunt。

我們可以使用Node的模塊系統(tǒng),而不需要額外的配置。讓我們移除<script>標(biāo)簽中的所有代碼到-現(xiàn)在是空的-app/renderer.js文件中。現(xiàn)在我們可以用一個<script> 標(biāo)記去引用renderer.js文件去替代之前的內(nèi)容。

列表2.9 從renderer.js加載JavaScript: ./app/index.html

                            +
<script>                    |使用Node的require函數(shù)
 require('./renderer'); <--+將額外的JavaScript模塊
</script>                   |加載到渲染器進(jìn)程中
                           +

如果我們啟動應(yīng)用程序,您將看到它的功能沒有改變。一切都照常進(jìn)行。這在軟件開發(fā)中很少發(fā)生。在繼續(xù)之前,讓我們先體驗一下這種感覺。

 

在渲染器進(jìn)程中添加樣式

當(dāng)我們在Electron應(yīng)用程序中引用樣式表時,很少會發(fā)生意外。稍后,我們將討論如何使用Sass而不是Electron。 在電子應(yīng)用程序中添加樣式表與在傳統(tǒng)web應(yīng)用程序中添加樣式表沒有多大不同。盡管如此,一些細(xì)微差別還是值得討論的。

讓我們從將style.css文件添加到應(yīng)用程序目錄開始。我們將以下內(nèi)容添加到style.css中。

列表2.10 添加基礎(chǔ)樣式: ./app/style.css

html {
 box+sizing: border+box;
}
*, *:before, *:after {
 box+sizing: inherit;        +使用頁面所運行
}                             |的操作系統(tǒng)的
body, input {                 |默認(rèn)系統(tǒng)字體
 font: menu;          <------+
}
?

最后一項聲明可能看起來有點陌生。它是Chromium獨有的,允許我們在CSS中使用系統(tǒng)字體。這種能力對于使我們的應(yīng)用程序與其原生本機(jī)程序相適應(yīng)非常重要。在macOS上,這是使用San Francisco的唯一方法,該系統(tǒng)字體附帶El Capitan 10.11及以后版本。

在Electron應(yīng)用程序中使用CSS,這是我們應(yīng)該考慮的另一個重要的區(qū)別。我們的應(yīng)用程序?qū)⒅辉趹?yīng)用程序附帶的Chromium版本中運行。我們不必?fù)?dān)心跨瀏覽器支持或兼容性考慮。正如在第1章中提到的,電子與相對較新版本的Chromium一起發(fā)布。這意味著我們可以自由地使用flexbox和CSS變量等技術(shù)。

我們像在傳統(tǒng)瀏覽器環(huán)境中一樣引用新樣式表,然后將以下內(nèi)容添加到index.html<head>部分。 我將包含鏈接到樣式表的HTML標(biāo)記—因為,在我作為web開發(fā)人員的20年里,我仍然不記得如何第一次嘗試就做到這一點。

列表2.11 在HTML文檔中引用樣式表: ./app/index.html

<link rel="stylesheet" href="style.css" type="text/css">

 

實現(xiàn)用戶界面

我們首先使用UI所需的標(biāo)記更新index.html。

列表2.12 為應(yīng)用程序的UI添加標(biāo)記: ./app/index.html

<h1>Bookmarker</h1>
<div class="error-message"></div>
<section class="add-new-link">
 <form class="new-link-form">
   <input type="url" class="new-link-url" placeholder="URL"size="100"
    required>
   <input type="submit" class="new-link-submit" value="Submit" disabled>
 </form>
</section>
?
<section class="links"></section>
<section class="controls">
 <button class="clear-storage">Clear Storage</button>
</section>

 

我們有一個用于添加新鏈接的部分,一個用于顯示所有精彩鏈接的部分,以及一個用于清除所有鏈接并重新開始的按鈕。你的應(yīng)用程序中的<script>標(biāo)簽應(yīng)該和我們在本章早些時候討論時一樣,但是以防萬一,我在下方給出代碼:

<script>
  require('./renderer');
</script>

 

標(biāo)記就緒后,我們現(xiàn)在可以將注意力轉(zhuǎn)向功能。讓我們清除app/renderer.js中的所有內(nèi)容,重新開始。在我們一起學(xué)習(xí)的過程中,我們將需要處理添加到標(biāo)記中的一些元素,所以讓我們首先查詢這些選擇器并將它們緩存到變量中。將以下內(nèi)容添加到app/renderer.js。

列表2.13 緩存DOM元素選擇器: ./app/renderer.js

const  linksSection = document.querySelector('.links');
const errorMessage = document.querySelector('.error-message');
const newLinkForm = document.querySelector('.new-link-form');
const newLinkUrl = document.querySelector('.new-link-url');
const newLinkSubmit = document.querySelector('.new-link-submit');
const clearStorageButton = document.querySelector('.clear-storage');

 

回顧清單2.12,您會注意到在標(biāo)記中我們將input元素的type屬性設(shè)置“url”。如果內(nèi)容不匹配有效的URL模式,Chromium將把該字段標(biāo)記為無效。不幸的是,我們無法訪問Chrome或Firefox中內(nèi)置的錯誤消息彈出框。這些彈出窗口不是Chromium web模塊的一部分,因此也不是Electron的一部分?,F(xiàn)在,我們在默認(rèn)情況下禁用start按鈕,然后在每次用戶在URL輸入框內(nèi)中鍵入字母時檢查是否有一個有效的URL語法。

如果用戶提供了一個有效的URL,那么我們將打開submit按鈕并允許他們提交URL。讓我們將這段代碼添加到app/renderer.js中。

 

列表2.14 添加事件監(jiān)聽器以啟用submit按鈕

newLinkUrl.addEventListener('keyup', () => {
 newLinkSubmit.disabled = !newLinkUrl.validity.valid;    <------+
});                        當(dāng)用戶在輸入字段中敲入url時               |
                          通過使用Chromium ValidityState API     |
                          來確定輸入是不是有效,如果是這樣,從         +
                submit按鈕中移除disable屬性

 

現(xiàn)在也是添加一個協(xié)助函數(shù)來清除URL字段內(nèi)容的好時機(jī)。在理想的情況下,只要成功存儲了鏈接,就會調(diào)用這個函數(shù)。

列表2.15 添加幫助函數(shù)來清除輸入框: ./app/renderer.js

                                   +
const clearForm= () => {           |通過設(shè)置新連接輸入框為空
 newLinkUrl.value = null;    <----+來清除該字段
};                                 |
                                  +
?

 

當(dāng)用戶提交一個鏈接,我們希望瀏覽器請求URL,然后把獲取回復(fù)體,解析它,找到title元素,得到標(biāo)題的文本元素,存儲書簽的標(biāo)題和URL在localStorage,和then-finally-update書簽的頁面。

 

在Electron實現(xiàn)跨域請求

你可能感覺到,也可能沒有感覺到,你脖子后面的一些毛發(fā)開始豎起來。你甚至可能對自己說:“這個計劃不可能行得通。您不能向第三方服務(wù)器發(fā)出請求。瀏覽器不允許這樣做?!?/p>

通常來說,你是對的。在傳統(tǒng)的基于瀏覽器的應(yīng)用程序中,不允許客戶端代碼向其他服務(wù)器發(fā)出請求。通常,客戶端代碼向服務(wù)器發(fā)出請求,然后將請求代理給第三方服務(wù)器。當(dāng)它返回時,它將響應(yīng)代理回客戶機(jī)。我們在第一章中討論了這背后的一些原因。

Electron具有Node服務(wù)器的所有功能,以及瀏覽器的所有功能。這意味著我們可以自由地發(fā)出跨源請求,而不需要服務(wù)器。

在Electron中編寫應(yīng)用程序的另一個好處是我們可以使用正在興起的Fetch API來向遠(yuǎn)程服務(wù)器發(fā)出請求。Fetch API免去了手工設(shè)置XMLHttpRequest的麻煩,并為處理我們的請求提供了一個良好的、基于承諾的接口。在撰寫本文時,主要瀏覽器對Fetch的支持有限。也就是說,它在當(dāng)前版本的Chromium中有完整的支持,這意味著我們可以使用它。

我們向表單添加一個事件偵聽器,以便在表單有動作時,立即執(zhí)行提交。我們沒有服務(wù)器,所以需要確保避免發(fā)出請求的默認(rèn)操作。我們通過防止默認(rèn)操作來做到這一點。我們還緩存URL輸入字段的值,以便將來使用。

 

列表2.16 向submit按鈕添加事件偵聽器: ./app/renderer.js

newLinkForm.addEventListener('submit', (event) => {
 event.preventDefault();              <-----+告訴Chromium不要觸發(fā)HTTP請求,
                                            |這是表單提交的默認(rèn)操作
 const url = newLinkUrl.value;  <--+        |
                                   |        +
// More code to come...             |獲取新鏈接輸入框中的URL字段,
});                                 +我們很塊就會用到這個值。
?

 

Fetch API作為全局可用的fetch變量。抓取的URL返回一個promise對象,該對象將在瀏覽器完成時被實現(xiàn) 獲取遠(yuǎn)程資源。使用這個promise對象,我們可以根據(jù)是否獲取網(wǎng)頁、圖像或其他類型的內(nèi)容來處理不同的響應(yīng)。在本例中,我們正在獲取一個網(wǎng)頁,因此我們將響應(yīng)轉(zhuǎn)換為文本。我們從事件監(jiān)聽器中的以下代碼開始。

列表2.17 使用Fetch API請求遠(yuǎn)程資源./app/renderer.js

fetch(url)  //使用Fetch API獲取提供的URL的內(nèi)容
.then(response => response.text()); //將響應(yīng)解析為純文本

 

Promises是鏈?zhǔn)降?,我們可以使用先前承諾的返回值,并將另一個調(diào)用附加到then。此外,response.text()本身返回一個promise。我們的下一步將是獲取接收到的大塊標(biāo)記,并解析它來遍歷它并找到title元素。

解析回復(fù)報文

Chromium提供了一個解析器,它將為我們做這件事,但是我們需要實例化它。在app/renderer的頂部。我們創(chuàng)建了一個DOMParser實例,并將其存儲起來供以后使用。

列表2.18 實例化一個DOMParser: ./app/renderer.js

const parser = new DOMParser(); //創(chuàng)建一個DOMParser實例。我們將在獲取所提供URL的文本內(nèi)容后使用此方法。

 

讓我們設(shè)置一對幫助函數(shù)來解析響應(yīng)并為我們找到標(biāo)題。

列表2.19 添加用于解析響應(yīng)和查找標(biāo)題的函數(shù): ./app/renderer.js

const parseResponse = (text) => {
return parser.parseFromString(text, 'text/html'); //從URL獲取HTML字符串并將其解析為DOM樹。
}
const findTitle = (nodes) =>{
return nodes.querySelector('title').innerText; //遍歷DOM樹以找到標(biāo)題節(jié)點。
}

 

現(xiàn)在我們可以將這兩個步驟添加到我們的處理鏈中。

列表2.20 解析響應(yīng)并在獲取頁面時查找標(biāo)題: ./app/renderer.js

fetch(url)
.then(response => response.text())
.then(parseResponse)
.then(findTitle);

 

此時,app/renderer.js中的代碼看起來是這樣的。

const parser = new DOMParser();
const linksSection = document.querySelector('.links');
const errorMessage = document.querySelector('.error-message');
const newLinkForm = document.querySelector('.new-link-form');
const newLinkUrl = document.querySelector('.new-link-url');
const newLinkSubmit = document.querySelector('.new-link-submit');
const clearStorageButton = document.querySelector('.clear-storage');
?
newLinkUrl.addEventListener('keyup', () => {
newLinkSubmit.disabled = !newLinkUrl.validity.valid;
});
?
newLinkForm.addEventListener('submit', (event) => {
event.preventDefault();
const url = newLinkUrl.value;
fetch(url)
.then(response => response.text())
.then(parseResponse)
.then(findTitle)
});
?
const clearForm = () => {
newLinkUrl.value = null;
}
?
const parseResponse = (text) => {
return parser.parseFromString(text, 'text/html');
}
?
const findTitle = (nodes) => {
return nodes.querySelector('title').innerText;
}

 

使用web storage APIs存儲響應(yīng)

localStorage是一個簡單的鍵/值存儲,內(nèi)置在瀏覽器中并持久保存之間的會話。您可以在任意鍵下存儲簡單的數(shù)據(jù)類型,如字符串和數(shù)字。讓我們設(shè)置另一個幫助函數(shù),它將從標(biāo)題和URL生成一個簡單的對象,使用內(nèi)置的JSON庫將其轉(zhuǎn)換為字符串,然后使用URL作為鍵存儲它。

圖2.22 創(chuàng)建一個函數(shù)來在本地存儲中保存鏈接: ./app/renderer.js

const storeLink = (title, url) => {
localStorage.setItem(url, JSON.stringify({ title: title, url: url }));
};

 

我們的新storeLink函數(shù)需要標(biāo)題和URL來完成它的工作,但是前面的處理只返回標(biāo)題。我們使用一個箭頭函數(shù)將對storeLink的調(diào)用封裝在一個匿名函數(shù)中,該匿名函數(shù)可以訪問作用域中的url變量。如果成功,我們也清除表單。

圖2.23 存儲鏈接并在獲取遠(yuǎn)程資源時清除表單: ./app/renderer.js

                                            
fetch(url)                                  
.then(response => response.text())        
.then(parseResponse)                       |
.then(findTitle)                           |將標(biāo)題和URL存儲到localStorage
.then(title => storeLink(title, url))  <---+
.then(clearForm);
?

 

顯示請求結(jié)果

存儲鏈接是不夠的。我們還希望將它們顯示給用戶。這意味著我們需要創(chuàng)建功能來遍歷存儲的所有鏈接,將它們轉(zhuǎn)換為DOM節(jié)點,然后將它們添加到頁面中。

讓我們從從localStorage獲取所有鏈接的能力開始。如果你還記得,localStorage是一個鍵/值存儲。我們可以使用對象。獲取對象的所有鍵。我們必須為自己提供另一個幫助函數(shù)來將所有鏈接從localStorage中取出。這沒什么大不了的,因為我們需要將它們從字符串轉(zhuǎn)換回實際對象。讓我們定義一個getLinks函數(shù)。

圖2.24 創(chuàng)建用于從本地存儲中獲取鏈接的函數(shù): ./app/renderer.js

                                       
                                     
const getLinks = () => {               |
                                      |獲取當(dāng)前存儲在localStorage中的所有鍵的數(shù)組
 return Object.keys(localStorage) <---+
  .map(key => JSON.parse(localStorage.getItem(key)));   <----+
}                                                              |對于每個鍵,獲取其值
                                                              |并將其從JSON解析為JavaScript對象
                                                             
?

 

接下來,我們將這些簡單的對象轉(zhuǎn)換成標(biāo)記,以便稍后將它們添加到DOM中。我們創(chuàng)建了一個簡單的convertToElement 幫助函數(shù),它也可以處理這個問題。需要指出的是,我們的convertToElement函數(shù)有點幼稚,并且不嘗試清除用戶輸入。理論上,您的應(yīng)用程序很容易受到腳本注入攻擊。這有點超出了本章的范圍,所以我們只做了最低限度的渲染這些鏈接到頁面上。我將把它作為練習(xí)留給讀者來確保這個特性的安全性。

列表2.25 創(chuàng)建一個從鏈接數(shù)據(jù)創(chuàng)建DOM節(jié)點的函數(shù): ./app/renderer.js

const convertToElement = (link) => {
return `
<div class="link">
<h3>${link.title}</h3>
<p>
<a href="${link.url}">${link.url}</a>
</p>
</div>
`;
};

 

最后,我們創(chuàng)建一個renderLinks()函數(shù),它調(diào)用getLinks,連接它們,使用convertToElement()轉(zhuǎn)換集合,然后替換頁面上的linksSection元素。

列表2.26 創(chuàng)建一個函數(shù)來呈現(xiàn)所有鏈接并將它們添加到DOM中: ./app/renderer.js

const renderLinks = () => {
const linkElements = getLinks().map(convertToElement).join(''); //將所有鏈接轉(zhuǎn)換為HTML元素并組合它們
linksSection.innerHTML = linkElements; //用組合的鏈接元素替換links部分的內(nèi)容
};

 

現(xiàn)在我們可以往處理鏈上添加最后一步。

列表2.27 獲取遠(yuǎn)程資源后呈現(xiàn)鏈接: ./app/renderer.js

fetch(url)
.then(response => response.text())
.then(parseResponse)
.then(findTitle)
.then(title => storeLink(title, url))
.then(clearForm)
.then(renderLinks);

 

當(dāng)頁面初始加載時,我們還通過在頂層范圍內(nèi)調(diào)用renderLinks()來呈現(xiàn)所有鏈接。

列表2.28 加載和渲染鏈接: ./app/renderer.js

renderLinks();  //一旦頁面加載,就調(diào)用我們之前創(chuàng)建的renderLinks()函數(shù)

 

使用promise與將功能分解為命名的幫助函數(shù)相協(xié)調(diào)的一個優(yōu)點是,我們的代碼通過獲取外部頁面、解析它、存儲結(jié)果和重新對鏈接列表進(jìn)行排序的過程非常清楚。

最后一件事,我們需要完成我們的簡單應(yīng)用程序的所有功能安裝的方法是連接“清除存儲”按鈕。我們在localStorage上調(diào)用clear方法,然后在linksSection中清空列表。

列表2.29 編寫清除存儲按鈕: ./app/renderer.js

clearStorageButton.addEventListener('click', () => {
localStorage.clear(); //清空localStorage中的所有鏈接
linksSection.innerHTML = '';    //從UI上移除所有鏈接
});

 

有了Clear Storage按鈕,似乎我們已經(jīng)具備了大部分功能。我們的應(yīng)用程序現(xiàn)在看起來如圖2.8所示。此時,呈現(xiàn)器過程的代碼應(yīng)該如清單2.30所示。

列表2.30 獲取、存儲和呈現(xiàn)鏈接的渲染器進(jìn)程: ./app/renderer.js

const parser = new DOMParser();
const linksSection = document.querySelector('.links');
const errorMessage = document.querySelector('.error-message');
const newLinkForm = document.querySelector('.new-link-form');
const newLinkUrl = document.querySelector('.new-link-url');
const newLinkSubmit = document.querySelector('.new-link-submit');
const clearStorageButton = document.querySelector('.clear-storage');
const newLinkUrl.addEventListener('keyup', () => {
const newLinkSubmit.disabled = !newLinkUrl.validity.valid;
});
newLinkForm.addEventListener('submit', (event) => {
event.preventDefault();
   
const url = newLinkUrl.value;
   
fetch(url)
.then(response => response.text())
.then(parseResponse)
.then(findTitle)
.then(title => storeLink(title, url))
.then(clearForm)
.then(renderLinks);
});
?
clearStorageButton.addEventListener('click', () => {
localStorage.clear();
linksSection.innerHTML = '';
});
?
const clearForm = () => {
newLinkUrl.value = null;
}
?
const parseResponse = (text) => {
return parser.parseFromString(text, 'text/html');
}
?
const findTitle = (nodes) => {
return nodes.querySelector('title').innerText;
}
?
const storeLink = (title, url) => {
localStorage.setItem(url, JSON.stringify({ title: title, url: url }));
}
?
const getLinks = () => {
return Object.keys(localStorage)
.map(key => JSON.parse(localStorage.getItem(key)));
}
?
const convertToElement = (link) => {
return `<div class="link"><h3>${link.title}</h3>
<p><a href="${link.url}">${link.url}</a></p></div>`;
}
?
const renderLinks = () => {
const linkElements = getLinks().map(convertToElement).join('');
linksSection.innerHTML = linkElements;
}
?
renderLinks();

 

錯誤的請求路徑

到目前為止,一切似乎都運轉(zhuǎn)良好。我們的應(yīng)用程序從外部頁面獲取標(biāo)題,在本地存儲鏈接,在頁面上呈現(xiàn)鏈接,并在需要時從頁面中清除它們。

但是如果出了什么問題呢?如果我們給它一個無效鏈接會發(fā)生什么?如果請求超時會發(fā)生什么?我們將處理兩種最可能的情況:當(dāng)用戶提供一個URL,該URL通過了輸入字段的驗證檢查,但實際上并不有效;當(dāng)URL有效,但服務(wù)器返回400或500級錯誤時。

我們添加的第一件事是處理任何錯誤的能力。我們需要提供一個捕獲異常的方法,當(dāng)出現(xiàn)錯誤的時候,進(jìn)行調(diào)用。我們在這個事件中定義了另一個幫助方法。

圖2.31 顯示錯誤消息: ./app/renderer.js

const handleError = (error, url) => {                     +如果獲取鏈接失敗,
  errorMessage.innerHTML = `                             |則設(shè)置錯誤消息元素的內(nèi)容
  There was an issue adding "${url}": ${error.message}   |         +
  `.trim();                                         <----+         |
  setTimeout(() => errorMessage.innerText = null, 5000);      <----+5秒后清除錯誤消息
}                                                                   +
?

 

我們可以把它加到鏈上。我們使用另一個匿名函數(shù)傳遞帶有錯誤消息的URL。這主要是為了提供更好的錯誤消息。如果不希望在錯誤消息中包含URL,則沒有必要這樣做。

圖2.32 在獲取、解析和呈現(xiàn)鏈接時捕獲錯誤: ./app/renderer.js

fetch(url)
 .then(response => response.text())
 .then(parseResponse)                          +
 .then(findTitle)                              |
 .then(title => storeLink(title, url))         |如果此處理鏈中的任何錯誤拒絕或拋出錯誤
 .then(clearForm)                              |則捕獲錯誤并將其顯示在UI中
 .then(renderLinks)                            |
 .catch(error => handleError(error, url));  <--+
?

 

我們還在前面添加了一個步驟,用于檢查請求是否成功。如果是,它將請求傳遞給處理鏈中的下一個操作。如果沒有成功,那么我們將拋出一個錯誤,這將繞過處理鏈中的其余操作,并直接跳到handleError()步驟。這里有一個我沒有處理的異常情況:如果Fetch API不能建立網(wǎng)絡(luò)連接,那么它返回的承諾將被完全拒絕。我把它作為練習(xí)留給讀者來處理,因為我們在這本書中有很多內(nèi)容要講,而且頁數(shù)有限。響應(yīng)。如果狀態(tài)碼在400或500范圍內(nèi),response.ok將為false。

圖2.33 驗證來自遠(yuǎn)程服務(wù)器的響應(yīng): ./app/renderer.js

                                                    +
                                                   |如果響應(yīng)成功,則將其
const validateResponse = (response) => {            |傳遞給下一個處理鏈
 if (response.ok) { return response; }        <-----+
 throw new Error(`Status code of ${response.status} +
  ${response.statusText}`);           <-----+
}                                            |如果請求收到400或500系列響應(yīng)
                                           +則引發(fā)錯誤。
?

 

如果沒有錯誤,此代碼將傳遞響應(yīng)對象。但是,如果出現(xiàn)錯誤,它會拋出一個錯誤,handleError()會捕捉到這個錯誤并相應(yīng)地進(jìn)行處理。

圖2.34 在處理鏈中添加validateResponse(): ./app/renderer.js

fetch(url)
.then(validateResponse)
.then(response => response.text())
.then(parseResponse)
.then(findTitle)
  .then(title => storeLink(title, url))
.then(clearForm)
.then(renderLinks)
.catch(error => handleError(error, url));

 

一個意想不到的錯誤

我們還沒有走出困境——如果一切順利的話,我們還有一個問題。如果單擊應(yīng)用程序中的一個鏈接會發(fā)生什么?也許并不奇怪,它指向了那個鏈接。我們的Electron應(yīng)用程序的Chromium部分認(rèn)為它是一個web瀏覽器,所以它做了web瀏覽器最擅長的事情—它進(jìn)入頁面。

只是我們的應(yīng)用程序并不是真正的web瀏覽器。它缺少后退按鈕或位置欄等重要功能。如果我們點擊應(yīng)用程序中的任何鏈接,我們就會幾乎被困在那里。我們唯一的選擇是關(guān)閉應(yīng)用程序,重新開始。

解決方案是在真正的瀏覽器中打開鏈接。但這引出了一個問題,哪個瀏覽器?我們?nèi)绾沃烙脩魧⑹裁丛O(shè)置為默認(rèn)瀏覽器?我們當(dāng)然不想做任何僥幸的猜測,因為我們不知道用戶安裝了什么瀏覽器,而且沒有人喜歡看到錯誤的應(yīng)用程序僅僅因為他們點擊了一個鏈接就開始打開。 ? Electron隨shell模塊一起載運,shell模塊提供了一些與之相關(guān)的功能,高級桌面集成。shell模塊可以詢問用戶的操作系統(tǒng)他們更喜歡哪個瀏覽器,并將URL傳遞給要打開的瀏覽器。讓我們從引入Electron開始,并在app/renderer.js的頂部存儲對其shell模塊的引用。

列表2.35 引用Electron的shell 模塊: ./app/renderer.js

const {shell} = require('electron');

 

我們可以使用JavaScript來確定我們希望在應(yīng)用程序中處理哪些url,以及我們希望將哪些url傳遞給默認(rèn)瀏覽器。在我們的簡單應(yīng)用程序中,區(qū)別很簡單。我們希望所有的鏈接都在默認(rèn)瀏覽器中打開。這個應(yīng)用程序中正在添加和刪除鏈接,因此我們在linksSection元素上設(shè)置了一個事件監(jiān)聽器,并允許單擊事件彈出。如果目標(biāo)元素具有href屬性,我們將阻止默認(rèn)操作并將URL傳遞給默認(rèn)瀏覽器。

列表2.36 在默認(rèn)瀏覽器中打開鏈接: ./app/renderer.js

                                                     +
                                                    |通過查找href屬性
                                                    |檢查被單擊的元素是否為鏈接
linksSection.addEventListener('click', (event) => {  |
 if (event.target.href) {                       <---+
   event.preventDefault();                    <----+
   shell.openExternal(event.target.href); <--+     |如果它不是一個連接,
}                                           |     |不打開
Uses Electron’s shell module                  |     +
});                 在默認(rèn)瀏覽器中使用Electorn   |
                    打開鏈接                   +
?

 

通過相對簡單的更改,我們的代碼的行為就像預(yù)期的那樣。單擊鏈接將在用戶的默認(rèn)瀏覽器中打開該頁。我們有一個簡單但功能齊全的桌面應(yīng)用程序了。

我們完成的代碼應(yīng)該如下面的代碼示例所示。你可能以不同的順序使用您的功能。

列表2.37 完成的應(yīng)用程序: ./app/renderer.js

const {shell} = require('electron');
?
const parser = new DOMParser();
?
const linksSection = document.querySelector('.links');
const errorMessage = document.querySelector('.error-message');
const newLinkForm = document.querySelector('.new-link-form');
const newLinkUrl = document.querySelector('.new-link-url');
const newLinkSubmit = document.querySelector('.new-link-submit');
const clearStorageButton = document.querySelector('.clear-storage');
?
newLinkUrl.addEventListener('keyup', () => {
 newLinkSubmit.disabled = !newLinkUrl.validity.valid;
});
?
newLinkForm.addEventListener('submit', (event) => {
 event.preventDefault();
?
 const url = newLinkUrl.value;
?
 fetch(url)
  .then(response => response.text())
  .then(parseResponse)
  .then(findTitle)
  .then(title => storeLink(title, url))
  .then(clearForm)
  .then(renderLinks)
  .catch(error => handleError(error, url));
});
?
clearStorageButton.addEventListener('click', () => {
 localStorage.clear();
 linksSection.innerHTML = '';
});
?
linksSection.addEventListener('click', (event) => {
 if (event.target.href) {
   event.preventDefault();
   shell.openExternal(event.target.href);
}
});
?
?
const clearForm = () => {
 newLinkUrl.value = null;
}
?
const parseResponse = (text) => {
 return parser.parseFromString(text, 'text/html');
}
?
const findTitle = (nodes) => {
 return nodes.querySelector('title').innerText;
}
?
const storeLink = (title, url) => {
 localStorage.setItem(url, JSON.stringify({ title: title, url: url }));
}
?
const getLinks = () => {
 return Object.keys(localStorage)
              .map(key => JSON.parse(localStorage.getItem(key)));
}
?
const convertToElement = (link) => {
 return `<div class="link"><h3>${link.title}</h3>
         <p><a href="${link.url}">${link.url}</a></p></div>`;
}
?
const renderLinks = () => {
 const linkElements = getLinks().map(convertToElement).join('');
 linksSection.innerHTML = linkElements;
}
?
const handleError = (error, url) => {
 errorMessage.innerHTML = `
   There was an issue adding "${url}": ${error.message}
 `.trim();
 setTimeout(() => errorMessage.innerText = null, 5000);
}
?
const validateResponse = (response) => {
 if (response.ok) { return response; }
 throw new Error(`Status code of ${response.status} ${response.statusText}`);
}
?
renderLinks();

 

總結(jié)

  • Electron不推薦或強(qiáng)制執(zhí)行特定的項目結(jié)構(gòu)。

  • Electron使用npm的package.json清單來決定那個文件被加載作為主進(jìn)程

  • 我們通過使用npm init從樣板文件中生產(chǎn)package.json

  • 我們通常在每個項目中都在本地安裝Electron。這允許我們有特定項目版本的Electron。

  • 我們可以在Electron應(yīng)用程序中使用require('electron')來訪問Electron特定的模塊和功能。

  • app模塊管理電子應(yīng)用的生命周期。

  • 主進(jìn)程無法呈現(xiàn)UI。

  • 我們可以使用Browser-window模塊從主進(jìn)程創(chuàng)建渲染進(jìn)程

  • Electron允許我們直接從第三方服務(wù)器發(fā)出請求,并不需要中間服務(wù)器的代理。傳統(tǒng)的web應(yīng)用程序則不允許這樣做。

  • 在localStorage中存儲數(shù)據(jù)將允許它在我們退出并重新打開時保持。

 

我的博客即將同步至騰訊云+社區(qū),邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=2zcuec310v8kg

原文出處:https://www.cnblogs.com/sanshengshui/p/11066103.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多