Electron開發初體驗

需求背景

平時總會寫markdown,markdown總體語法用起來很方便,但依然有晦澀的地方,好比表格。markdown的表格語法寫起來很容易出錯,並且每行每列單元格里的內容長短不一編輯器裏就很容易亂掉,因此我在寫表格時候都是藉助Tables Generator來寫的,可是這個網站不能保存多個模板,每次寫不一樣的表格都要把列數,表頭信息來回改,很麻煩,因而打算本身照着Table Generator寫一個簡單的,能保存表頭信息的東西出來。先看一哈大體的樣子:css

動手前的思考

最初在考慮的是要不要寫一個差很少的簡單的頁面,可是我我的不太喜歡總開新的tab來回切換,因此忽然想到能夠作成一個簡單的桌面應用,想用的時候能夠直接從Dock啓動,並且Electron有了解過但沒實際用過,也能夠嚐嚐鮮,就決定用Electron直接作成一個小應用了。html

工程搭建

在這個"不用腳手架不舒服" + "不用框架不舒服"的時代,搭建工程固然是選擇一款靠譜的腳手架了,開發環境 + 打包構建都能經過命令行搞定,極大程度地節省了時間,感謝開源貢獻者吧~這裏我選擇了electron-vue這個模板,基於vue-cli的,初始化項目很簡單,直接執行:前端

vue init simulatedgreg/electron-vue my-project

而後根據提示輸入完項目名,項目描述,依賴和構建工具(electron-builder或者electron-packager)後,一個項目就搭建完成了,進入目錄執行:vue

yarn && yarn dev

而後項目就以開發模式運行起來了git

後續的開發工做,若是你的應用對於系統級別的API需求不大,事實上和開發網頁的體驗並無什麼區別。好比我要完成的這個小工具就和開發網頁的體驗差很少。github

核心概念

實現的思路比較簡單:爲表格的每個單元格設置contenteditable,這樣整個表格的內容都是能夠隨意編輯的,而後再經過MutationObserver監聽表格內容的變化,構造出正確的數據結構便可。web

爲th和td添加 contenteditable 使其內容能夠編輯:vue-cli

<table id="table">
    <tbody>
      <tr>
        <th class="col-mark"></th>
        <th data-row="0" :data-col="index" v-title="item.text"
          v-for="(item, index) in columns" :key="item.key" contenteditable
          :class="{'active': index === acCol}"
        ></th>
      </tr>
    </tbody>
</table>

而後在渲染完成後使用MutationObserver監聽變化:markdown

mounted () {
    this.targetNode = document.getElementById('table')
    // this.handleMutation是具體處理回調
    this.observer = new MutationObserver(this.handleMutation)
    this.observer.observe(this.targetNode, this.config)
}

這裏的MutationObserver的配置是{ subtree: true, characterData: true, childList: true }做用分別是:數據結構

  • characterData: 目標的數據被修改時觸發,好比直接編輯td,th裏的內容時,就是對其textContent的修改。
  • subtree: 使MutationObserver也能響應後代元素內容的變化,由於咱們只在table上綁定一個MutationObserver,因此使用這個屬性。
  • childList: 目標(包括後代節點)的子元素(包括文本元素)添加或者被刪除時觸發。好比單元格中的內容從無到有和從有到無的兩種邊界狀況。

核心概念主要就用到了這兩個概念,樣式上選擇了papercss,簡單的功能搭配簡潔的風格。

複製到剪貼板

表格信息寫好以後,最後的功能就是生成對應的markdown內容而後複製到粘貼板了。Electron提供了clipboard API,直接調用clipboard.writeText就能把內容寫入粘貼板:

import { clipboard } from 'electron'

let text = 'xxx'
clipboard.writeText(text)

這裏複製成功後能夠給出一個提示信息,咱們在Electron開發的內容通常是在render進程的,在render進程中能夠直接使用HTML5 Notification API來實現提示:

let myNotification = new Notification('Table Generator', {
    body: 'Copy successfully~'
})
setTimeout(() => {
    myNotification.close()
}, 2000)

實際效果爲一個兩秒後自動消失的提示框:

主進程與渲染進程的通訊

這裏要實現的效果是經過自定義的快捷鍵刪除左側模板列表中的模板,可是快捷鍵註冊只能在主進程經過globalShortcut註冊,而對於刪除行爲的響應(二次確認的彈窗)是在渲染進程,因此設計到了主進程和渲染進程的通訊。

渲染進程是主進程中建立的一個BrowserWindow實例,實例的webContents屬性是對渲染進程的引用,因此主進程能夠直接經過webContents發送事件:

// 建立的渲染進程
mainWindow = new BrowserWindow({
    height: 560,
    minHeight: 450,
    width: 1000,
    minWidth: 760,
    titleBarStyle: 'hiddenInset',
    show: false,
    backgroundColor: '#fff'
})
// 註冊快捷鍵
globalShortcut.register('Cmd+D', () => {
    // 直接經過mainWindow.webContents發送事件
    mainWindow.webContents.send('del-tpl')
})

而在對應的render進程,能夠經過ipcRenderer監聽消息:

ipcRenderer.on('del-tpl', () => {
  // 觸發modal彈出
  this.$refs['del-btn'].click()
})

一些簡單的優化

事實上經過一些簡單的配置,就可讓你的應用體驗更好:

  • 建立無邊框窗口:無邊框窗口會讓應用總體變得更美觀,在建立BrowserWindow時經過titleBarStyle: 'hiddenInset'實現(針對Mac系統)
  • 在建立BrowserWindow時經過show: false隱藏窗口,在'ready-to-show'事件觸發時手動調用窗口實例的show()方法,保證窗口渲染完再展現。
  • 經過將窗口背景顏色設置成渲染進程背景同樣的顏色,讓應用顯得更快。

總結

本次初步的嘗試並無用到太多系統級別的API,基本和開發Web頁面體驗同樣,文中提到的API和優化點都是文檔上能夠找到的,本次實踐只是對Electron的一次涉獵,後續能夠考慮將各類操做和提示都遷移到原生的API,或者再加入其它功能,不過用來生成markdown內容「初心」已經達到了~

源碼在GayHub上,有興趣的同窗也能夠本身安裝依賴構建體驗一哈,順便點個star~最後,咱們在招前端開發,歡迎投遞簡歷至hzchenjinghui@corp.netease.com!

相關文章
相關標籤/搜索