陽光正好Electron今天出發

陽光正好Electron今天出發

本文閱讀須要花費一點時間,若是時間緊迫者能夠閱讀開頭以及結尾總結。thanks
來咿呀快活呀html


首先問一點問題

  1. 什麼是Electron
  2. Electron是用來幹什麼的,解決些什麼
  3. 寫個todo看看得怎麼玩?
  4. 怎麼實現桌面程序,概念意義,底層的技術大概是什麼?

第一步 如何安裝

首先咱們的選擇能夠在save在開發依賴上
npm install electron --save-dev
也能夠全局安裝electron
npm install electron -g

這裏有一段文檔翻譯有意思的話

Electron 可讓你使用純 JavaScript 調用豐富的原生(操做系統) APIs 來創造桌面應用。 你能夠把它看做一個專一於桌面應用的 Node. js 的變體,而不是 Web 服務器。java

這不意味着 Electron 是綁定了 (GUI) 庫的 JavaScript。 相反,Electron 使用 web 頁面做爲它的 GUI,因此你能把它看做成一個被 JavaScript 控制的,精簡版的 Chromium 瀏覽器。

awesomenode

第二步 瞭解基本概念

Electron 分主進程與渲染進程

主進程運行package.json 的main腳本被成爲主進程。運行在主進程中的腳本將以建立 web 頁面的方式顯示一個 GUI。
(這讓我想起了。之前作python 跟java時候gui主線程的感受。。。)python

Electron的web頁面運行在一個成爲渲染進程的進程中。 而且在頁面與操做系統中得到一些低級別的交互git

主進程 渲染進程 區別

主進程使用BrowserWindow實例建立頁面github

每一個 BrowserWindow實例都在本身的渲染進程裏運行頁面。 web

當一個 BrowserWindow 實例被銷燬後,相應的渲染進程也會被終止。chrome

渲染進程相互獨立,主進程管理。npm

渲染進程只須要關心它們本身的頁面。json

網頁內是不能進行GUI操做的。

須要對應的渲染進程與主進程之間通訊。

通訊方法

一、使用HTML5 API 例如storage API、localstorage、sessionstorage或IndexedDB

二、IPC通訊( ipcRenderer 和 ipcMain)

三、RPC通訊(remote模塊)

下面介紹實現一個todolist

首先編碼開始。

它管控文件與package.json相似。

主線程由main定義的入口文件建立

如下是不完整代碼。大概的。

須要完整代碼能夠查看github地址。

todolist

項目目錄大概爲
todo
-- addWindow.html
-- main.js
-- package.json
-- window.html

入口文件是咱們的main.js,它是一個應用中的中心調度。

// 能夠向使用nodejs時同樣引入模塊
// 這個也就是所謂的主進程,看起來就像是nodejs腳本
const electron = require('electron');
const url = require('url');
const path = require('path');


const {app,BrowserWindow,Menu,ipcMain} = electron;

//設置環境
process.env.NODE_ENV = 'production';

let mainWindow;
let addWindow;
//listen for app to be ready

app.on('ready',function(){
    //1. 建立一個新的窗口
    mainWindow = new BrowserWindow({});
    //加載 html進窗口
    mainWindow.loadURL(url.format({
        pathname: path.join(__dirname,'window.html'),
        protocol: 'file:', //協議
        slashes:true
    }));
    //file:/dirname/mainWindow.html

    //6. 大窗口關閉整個程序關閉
    mainWindow.on('close',function(){
        app.quit();
    })

    //2 .設置菜單
    const mainMenu = Menu.buildFromTemplate(mainMenuTemplate);
    Menu.setApplicationMenu(mainMenu);

})


//handle create add window 

function createAddWindow(){
    //5. 新建窗口
    addWindow = new BrowserWindow({
        width: 300,
        height: 200,
        title: 'Add TODO list item'
    });
    //load html into window
    addWindow.loadURL(url.format({
        pathname: path.join(__dirname,'addWindow.html'),
        protocol: 'file:', //協議
        slashes:true
    }));
    // 垃圾回收
    addWindow.on('close',function(){
        addWindow = null;
    })
}

//7. 捕獲子窗口ipc item:add
// IPC通訊
ipcMain.on('item:add',function(e,item){
    console.log('item');
    mainWindow.webContents.send('item:add',item);
    addWindow.close();
});

const mainMenuTemplate = [{
    label: 'File',
    submenu: [//3. 設置子菜單
        {
            label: 'Add Item',
            click(){
                //4. 新建窗口
                createAddWindow();
            }

        },
        {
            label: 'Clear Items',
            click(){
                mainWindow.webContents.send('item:clear');
            }
        },
        {
            label: 'Quit',
            accelerator: process.platform =='darwin'? 'Commond+Q':'Ctrl+Q',//快捷鍵作os版本區分
            click(){
                app.quit();
            }
        }
    ]
}];


// if mac , add empty object to menu
if(process.platform =='darwin'){
    mainMenuTemplate.unshift({});
}


// 區分開發環境
if(process.env.NODE_ENV !== 'production'){
    // add devtools
    mainMenuTemplate.push({
        label:'Developer tools',
        submenu:[
            {
                role:'reload'
            },
            {
                label: 'Toggle DevTools',
                accelerator: process.platform =='darwin'? 'Commond+I':'Ctrl+I',//快捷鍵作os版本區分,
                click(item,focusedWindow){
                    //區分點擊窗口
                    focusedWindow.toggleDevTools();
                }
            }
        ]
    });
}

主進程設置好ipc通訊口。
監控渲染進程對應事件

addWindow.html

<div class="container">
            <form>
                    <div>
                        <label>
                            Enter Item
                        </label>
                        <input type="text" id="item" autofocus>
                    </div>
                    <button class="btn waves-effect waves-light" type="submit">add Item</button>
                    <!-- 將item發送到mainWindow -->
                </form>
    </div>
    
    
        const electron = require('electron');
        const {ipcRenderer} = electron;
        
        const form = document.querySelector('form');
        form.addEventListener('submit',function(e){
            e.preventDefault();
            // console.log(123);
            const item = document.querySelector('#item');
            ipcRenderer.send('item:add',item.value);
            //使用ipc進行通訊
            
        })

主進程渲染頁面

<nav>
        <div class="nav-wrapper">
            <a class="brand-logo center">
                TODO LIST
            </a>
        </div>
    </nav>
    <ul id="mainContainer">

    </ul>


    <script>
        const electron = require('electron');
        const {ipcRenderer} = electron;
        const ul = document.querySelector('#mainContainer');
        ipcRenderer.on('item:add',function(e,item){
            ul.className = 'collection';
            const li = document.createElement('li');
            li.className = 'collection-item';
            const itemText = document.createTextNode(item);
            li.appendChild(itemText);
            // const li = '<li class="collection-item">'+item+'</li>';
            ul.appendChild(li);  
            // ul.innerHTML = ul.innerHTML+li;     
        })
        //clear items
        ipcRenderer.on('item:clear',function(e){
            ul.innerHTML = '';
            // if(ul.clildren.length == 0){
                ul.className = '';
            // }
        })
        // Remove item by doubleclick
        ul.addEventListener('dblclick',function(e){
            e.target.remove();
            // console.log(ul.clildren.length);
            if(ul.children.length == 0){
                ul.className = '';
            }
        })
    </script>

demo總結

大概能夠瞭解

  • 可使用node模塊
  • 渲染界面可使用web頁面渲染
  • 瞭解進程間的通訊

調試

渲染進程的調試

渲染進行的調試能夠經過webContent的openDevTool api打開,調試web頁面

const { BrowserWindow } = require('electron')
  
let win = new BrowserWindow()
win.webContents.openDevTools()

主進程調試

命令行開關
--inspect=[port]
監聽 V8 引擎中有關 port 的調試器協議信息

--inspect-brk=[port]
和--inspector 同樣,可是會在JavaScript 腳本的第一行暫停運行。
外部調試器
  • 經過訪問 chrome://inspect 來鏈接 Chrome 並在那裏選擇須要檢查的Electron 應用程序。
  • 使用 VSCode 進行主進程調試

(感受這裏有點想傳統的debug nodejs in browser)


chromium

由於是使用chromium結合,因此咱們同時也可使用HTML5新特性在咱們渲染進程裏
例如離線通知,離線緩存等。


總結

  • Electron 是一個能夠用 JavaScript、HTML 和 CSS 構建桌面應用程序的庫
  • 能夠多端兼容(一套代碼)
  • Chromium、Node.js 、調用操做系統本地功能的 API
  • 無縫使用Node

一些連接


在這些地方能夠找到我

題外話

本文寫成較早,有些不妥之處還望諒解(2017年)

若有疑惑歡迎討論。

相關文章
相關標籤/搜索