基於Vue+Electron構建桌面應用程式實踐
Electron 是由 GitHub 開發的開源庫,用於構建擁有 HTML、CSS 和 JavaScript 的跨平臺桌面應用程式。Electron 通過把 Chromium 和 Node.js 組合到一個執行時來實現這一點,並且可以為 Mac、Windows 和 Linux 打包應用程式 。
為了快速入門,我使用了 Greg Holguin 的 electron-vue 樣板。它給開發人員提供了 vue-cli scanffolding、常見的 Vue 外掛、打包器、測試、開發工具和其他功能。
我們要構建什麼?
我們要構建一個跟上一篇文章中所述的一樣的應用程式,基於 OpenWeatherMap API 的該應用程式用來檢視使用者所選擇城市的天氣情況。
如果只想檢視 Electron 支援的應用程式最終程式碼,請點選這裡:
ofollow,noindex">https://github.com/NataliaTepluhina/Vue-Desktop-App/tree/electron
安裝
Electron-vue 樣板是作為 VueCLI 2.x 的模板構建的,包括自定義應用程式的選項。因此,需要進行全域性安裝:
npm install -g vue-cli
如果喜歡用 VueCLI 的最新版本,就需要安裝全域性網橋:
npm install -g @vue/cli @vue/cli-init
然後,初始化你的專案:
vue init simulatedgreg/electron-vue weather-app
這將啟動一個安裝專案,其中包括需要你做出的幾個選擇。

其中很酷的是,如果需要一些常用的外掛和庫,比如 axios,可以在安裝過程中選擇它們。
幾乎所有的選擇都很明確,但是有一個問題:

我決定搜尋一下,在 StackOverflow 上找到了一個有用的線索。根據這個線索,看起來 electron 構建器(electron-builder)更適合我,因此,我就改用它了。
設定專案後,需要開啟應用程式所在的資料夾,執行 npm install 或 yarn install,現在我們準備好了。
瞭解應用程式結構
安裝完成後,可以在 src 中看到兩個資料夾 main 和 renderer,Electron 主程序需要用到第一個。
根據 electron-vue 的文件,在 Electron 中執行 package.json 主指令碼的程序被稱為主程序。在主程序中執行的指令碼可以通過建立 web 頁面來顯示 GUI。
在 main 資料夾中有兩個檔案:index.js 和 index.dev.js。第一個是你的應用程式的主檔案,是 electron 啟動用的檔案。它也被用做 webpack 的生產入口檔案。所有主要的流程工作都應該從這裡開始。
而 index.dev.jsis 專門用於開發,因為它安裝了 electron-debug 和 vue-devtools。在開發應用程式時,可以不用理睬它。
另外,渲染器(renderer)程序需要 renderer 資料夾。
由於 Electron 使用 Chromium 來顯示 web 頁面,因此也用到了 Chromium 的多程序架構。Electron 中的每個 web 頁面都在自己的程序中執行,這些程序被稱為渲染器程序。
正如你可能注意到的是,它是個“正常的”Vue 應用程式結構,擁有 assets 和 components 資料夾:main.js 和 App.vue 檔案。這是後者的結構:
<template> <div id="app"> <landing-page></landing-page> </div> </template> <script> import LandingPage from '@/components/LandingPage' export default { name: 'weather-app', components: { LandingPage } } </script> <style> /* CSS */ </style>
如果嘗試執行 dev 任務,將會得到以下結果:

因此,這裡有一個登入頁面(landing-page)元件,也開啟了開發工具(devtools)。現在,我們可以改變它了。
快速構建(scaffolding)應用程式
與 Vuido 不同,Electron 支援的應用程式是用 HTML 標籤而不是用本機元件構建的。因此,我們將建立一個與通常的 web 應用程式類似的結構,並用 CSS 來進行樣式設計。
請注意:我沒有特意安裝任何 CSS 框架或元件庫:我希望在沒有新增任何不同的依賴項的情況下,比較一下包的大小。在兩個專案中唯一用到的庫是 axios。
第一步是去掉登入頁面元件。然後我添加了一個簡單的輸入欄位和一個按鈕:
<div id="app"> <p>Enter the city name to check current weather in it</p> <section class="weather-input"> <input type="text" v-model="query"> <button :disabled="!query.length">Check</button> </section> </div>

我們在資料中有個查詢(query)屬性來處理使用者輸入,我們將把該查詢作為引數,進行 API 呼叫。
進行 API 呼叫
我使用了 OpenWeatherMap 當前天氣 API。它提供很多不同的資訊,可以點選這裡檢視 JSON 響應的示例。
在安裝過程中,我們已經將 axios 包含在我們的應用程式中。我們來看看 src/renderer/main.js:
import Vue from 'vue'; import axios from 'axios'; import App from './App'; if (!process.env.IS_WEB) Vue.use(require('vue-electron')); Vue.http = Vue.prototype.$http = axios; Vue.config.productionTip = false;
因此,我們可以在元件例項中把 axios 方式用作 this.$http。在這裡,我們將只為我們的 API 呼叫新增一個基本 URL:
axios.defaults.baseURL = 'http://api.openweathermap.org/data/2.5';
現在,在 App.vue 中,我們將建立一組資料屬性來顯示不同的天氣資料:
data() { return { query: '', error: false, city: '', country: '', weatherDescription: '', temp: null, tempMin: null, tempMax: null, humidity: null, icon: '', }; },
與 Vuido 版本相比,我添加了一個額外屬性,它是個圖示。API 提供天氣圖示,但是我們無法在 Vuido 應用程式中使用,因為目前不支援顯示影象。
我們還建立了一種方法來獲取資料:
methods: { showWeather() { this.$http .get(`/weather?q=${this.query}&units=metric&&appid=${API_KEY}`) .then(response => { this.city = response.data.name; this.country = response.data.sys.country; this.weatherDescription = response.data.weather[0].description; this.temp = response.data.main.temp; this.tempMin = response.data.main.temp_min; this.tempMax = response.data.main.temp_max; this.humidity = response.data.main.humidity; this.icon = `http://openweathermap.org/img/w/${ response.data.weather[0].icon }.png`; this.error = false; }) .catch(() => { this.error = true; this.city = ''; }); }, },
並把它新增到按鈕的單擊回撥中:
<button :disabled="!query.length" @click="showWeather">Check</button>
現在,如果在輸入欄位輸入文字,單擊按鈕,就可以在“網路(Network)” 選項卡上觀察 API 呼叫:

顯示天氣資料
我們把這些資料新增到模板上:
<template> <main id="app"> <p>Enter the city name to check current weather in it</p> <section class="weather-input"> <input type="text" v-model="query"> <button :disabled="!query.length" @click="showWeather">Check</button> </section> <section v-if="error" class="weather-error"> There is no such city in the database </section> <section v-if="city.length" class="weather-result"> <h1>{{city}}, {{country}}</h1> <p><em>{{weatherDescription}}</em></p> <div class="weather-result__main"> <img :src="icon" alt="Weather icon"> <div class="weather-result__temp"> {{temp}}°C </div> </div> <div class="weather-result__details"> <p>Min: {{tempMin}}°C</p> <p>Max: {{tempMax}}°C</p> <p>Humidity: {{humidity}}%</p> </div> </section> </main> </template>
我們的應用程式檢視:

image
太棒了,我們能看到真實的天氣狀況了!但是,它看起來像是 1999 年的……我們給它新增點 CSS 魔法吧(事實上,是很多 CSS 魔法)!
<style lang="scss"> * { margin: 0; padding: 0; } html, body, #app { height: 100%; } #app { font-family: Arial, Helvetica, sans-serif; font-size: 16px; padding: 10px; background: rgb(212, 228, 239); background: -moz-radial-gradient( center, ellipse cover, rgba(212, 228, 239, 1) 0%, rgba(134, 174, 204, 1) 100% ); background: -webkit-radial-gradient( center, ellipse cover, rgba(212, 228, 239, 1) 0%, rgba(134, 174, 204, 1) 100% ); background: radial-gradient( ellipse at center, rgba(212, 228, 239, 1) 0%, rgba(134, 174, 204, 1) 100% ); filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#d4e4ef', endColorstr='#86aecc',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */ } .weather-input { display: flex; align-items: center; padding: 20px 0; } .weather-result { text-align: center; &__main { display: flex; align-items: center; justify-content: center; padding-top: 5px; font-size: 1.3rem; font-weight: bold; } &__details { display: flex; align-items: center; justify-content: space-around; color: dimgray; } } .weather-error { color: red; font-weight: bold; } input { width: 75%; outline: none; height: 20px; font-size: 0.8rem; } button { display: block; width: 25%; height: 25px; outline: none; border-radius: 5px; white-space: nowrap; margin: 0 10px; font-size: 0.8rem; } </style>
最終,我們擁有了這個美妙的全功能應用程式:

在打包之前,最後要做的事是把它的尺寸縮小到視窗大小。如果我們檢視一下 src/main/index.js 檔案,可以找到它的設定選項:
mainWindow = new BrowserWindow({ height: 563, useContentSize: true, width: 1000 })
我們把寬度改為 450,高度改為 250。
打 包
你可以把你的應用程式構建為 web 應用程式了!如果執行 build:web 任務,可以在 dist 資料夾中找到構建 web 應用程式。
但是,讓我們回到我們的桌面應用程式並執行構建任務。結果,你在構建資料夾中會有一個資料夾,該資料夾的名字是根據你的平臺命名的(對我而言是 mac),裡面有一個應用程式檔案。它的大小是 133Mb!

對於這麼小的應用程式來說,這檔案太大了。另外,如果執行一下,你就會注意到,它的啟動比 Vuido 支援的應用程式慢。
最終的樣子:

結 論
優點:
-
容易上手;
-
出色的文件;
-
提供 web 應用程式構建;
-
可以通過 CSS 樣式自定義。
缺點:
-
打包後的檔案超大;
-
比用本機 GUI 元件構建的應用程式速度慢;
-
如果你的應用程式需要獨特的外觀,並且你不在乎;
-
打包後的檔案大小和效能,那麼,Electron-vue 是個不錯的選擇。
更新
如果你的 web 應用程式是用 Vue CLI 3 構建的,則可以用 Vue CLI 外掛 Electron Builder 把它簡化成桌面應用程式。你只需在專案根資料夾中執行以下命令:
vue add electron-builder
執行結束後,你將會擁有兩個額外的 npm 任務:serve:electron 和 build:electron,與桌面應用程式一起工作。

本次給大家推薦一個免費的學習群,裡面概括移動應用網站開發,css,html,webpack,vue node angular以及面試資源等。
對web開發技術感興趣的同學,歡迎加入Q群:943129070,不管你是小白還是大牛我都歡迎,還有大牛整理的一套高效率學習路線和教程與您免費分享,同時每天更新視訊資料。
最後,祝大家早日學有所成,拿到滿意offer,快速升職加薪,走上人生巔峰。