[轉] electron實戰開發詳細流程


【From】 http://www.myk3.com/arc-8856.html

 

很久沒有更新博客,人越來越懶了,唉 說好做的electron教程距離上次玩electron已經過去了好幾個月了。。

 

    這次對electron做一個實戰流程的介紹,關於electron的介紹,可以看這里 http://www.myk3.com/arc-4486.html 

    關於electron的demo安裝,請看 http://www.myk3.com/arc-4483.html

    使用 electron 您需要有一定的nodejs使用基礎,能熟練使用js語言。那么,以這篇文檔http://www.myk3.com/arc-4486.html 的項目為例,來介紹其中用到的技巧和流程。

 

    思想:項目的界面采用html+css+js完成,關於頂部的標題欄和最大化最小化 關閉按鈕也是用html完成。后面說他們與electron 的交互。而electron 提供包含在線網頁的容器框架,一個electron窗口包含一個在線網頁。

 

    假如我們寫好了登錄頁面,這里面有如下的地方需要雨electron 交互 甚至與node模塊交互。分別是 點擊頁面中的新窗口打開的連接,會彈出新的無標題欄窗口,我們攔截點擊事件,讓其用默認瀏覽器打開。然后是自己寫的標題欄的拖動,最大化,最小化,關閉按鈕的響應。點擊登錄打開新窗口的響應。以及穿夠頁面加載完畢才顯示。 如果你的網頁載入很慢,建議html本地化,我這里的服務器性能不錯,所以直接在線加載,速度也不錯。

 

    那么對上面頁面中需要與electron 響應的功能,下面一一說明。

 

    先創建一個登錄窗口,並加載登錄頁面作為gui驅動。在main.js中寫。修改你安裝的demo中的createWindow方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function  createWindow () {
   mainWindow =  new  BrowserWindow({
       width: 500, //窗口寬度
        height: 600, //窗口高度
        resizable:  false , //能否改變窗體大小
         'accept-first-mouse' true ,
         title:  '佳樂社區' ,
         frame:  false ,
         show:  false , //是否顯示界面 先設置否
         //icon:'3.ico',
         hasShadow :  true
   })
   mainWindow.loadURL(baseUrl+ 'user.php?a=basic&f=login&app=1' )
}

 

    我們讓其加載完畢顯示,加上在載入完畢顯示的代碼

1
2
3
mainWindow.webContents.on(  'did-finish-load' function  () {
       mainWindow.show();
   });

    這樣登錄窗口就顯示了。接下來標題欄的拖動。很簡單在標題欄的html元素上加上 css

1
-webkit-app-region: drag;

    對於加上-webkit-app-region: drag;的元素,只能拖動,而我們的最大化最小化,關閉都包含在其中,我們讓他們可以點擊,單獨設置這幾個按鈕加上css

1
-webkit-app-region: no-drag;

    如圖:QQ截圖20160918100100.png

    

    當然,你也可以保留window的標題欄,這樣就不用自己寫事件處理了,不過,小安覺得自帶的太丑了,所以重寫。

    接下來對於頁面中target="blank"a連接彈出的新窗口做攔截,讓其用自帶的瀏覽器打開,如果用無標題欄的electron打開,很丑,具體思想,調用node的exec函數執行cmd,不過需要先攔截,具體代碼:

 

1
2
3
4
5
6
mainWindow.webContents.on(  'new-window' function  (event,url,fname,disposition,options) {
       var  exec = require( 'child_process' ).exec;  //加載node模塊  url是將要跳轉的地址
       //攔截url調用外部瀏覽器打開
       exec( 'start ' +url,  function (err,stdout,stderr){});
       event.preventDefault();
   });

    然后我們來看 最大化,最小化,關閉的處理

    這里要介紹下electron的ipc通信,具體的專業術語不知道,反正就是讓main.js和各個electron窗口之間能通信,互相控制,官方有個規則,一切的electron窗口原生操作都盡量在main.js中處理,這是安全的,雖然在各個electron窗口的html頁面也可以寫窗口的相關操作代碼。

 

    用實例來演示ipc的用法。main.js中創建了登錄的electron窗口,在點擊窗口中html寫的最小化按鈕時,觸發頁面js,我用jquery來綁定點擊事件

1
2
3
4
5
var  ipc = require( 'electron' ).ipcRenderer;
//綁定最小化
f.$doc.delegate( '.window_min' , 'click' , function (e){
         ipc.send( 'login-window-min' ); //發送了一個login-window-min的消息,這個消息將在 main.js中接受,名稱可以自定義。
     })

    記得在html頁面中使用ipc一定要先引用 

1
require( 'electron' ).ipcRenderer;

    而在main.js中不一樣,用這句 這里語法是es6,新一代的js語法,童鞋們可以學習下

1
const ipc = electron.ipcMain

    在main.js中處理接受到消息login-window-min 代碼如下:

1
2
3
4
//登錄窗口最小化
ipc.on( 'login-window-min' , function (){
     mainWindow.minimize();
})

    mainWindow是我們的登錄窗口創建后返回的句柄,它是全局的,所以在main.js的任何地方都可以用,它的定義是全局的

1
let mainWindow

    而最大化和關閉都差不多。

    完整代碼登錄的html中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
         f.$doc.delegate( '.window_close' , 'click' , function (e){
         ipc.send( 'login-window-close' );
     })
     f.$doc.delegate( '.window_min' , 'click' , function (e){
         ipc.send( 'login-window-min' );  
     })
     var  is_window_max =  false ;
     f.$doc.delegate( '.window_max' , 'click' , function (e){
         ipc.send( 'login-window-max' );
         if (is_window_max){
             is_window_max =  false ;
             $( this ).find( 'div' ).css( 'fontSize' , '24px' );
         } else {
             $( this ).find( 'div' ).css( 'fontSize' , '20px' );
             is_window_max =  true ;
         }  
     })

    main.js中的處理過程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//關閉所有窗口 調用ipc模塊 主進程
ipc.on( 'login-window-close' , function (){
     app.quit();
})
//登錄窗口最小化
ipc.on( 'login-window-min' , function (){
     mainWindow.minimize();
})
//登錄窗口最大化
ipc.on( 'login-window-max' , function (){
     if (mainWindow.isMaximized()){
         mainWindow.restore();  
     } else {
         mainWindow.maximize(); 
     }
})

    應為登錄窗口是主窗體,所以當登錄窗體關閉,應用結束,用 app.quit();

    接下來介紹登錄按鈕點擊后創建新electron窗口,在登錄html頁面中寫綁定,在ajax登錄驗證成功的回調中打開新窗體

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
                             success: function (r){
                     $( '#login-error' ).hide();
                     $( '#login-error' ).fadeIn(500); 
                     $( '.notice-descript' ).text(r.msg);
                     if (r.status){
                         //檢查是否記住密碼
                         lo.remember_pwd();
                         //如果是軟件登錄則打開內容窗口
                         if (f.app){
                             ipc.send( 'content-window-show' ,r.data);
                             setTimeout( function (){
                                 $( '#fm-login-submit' ).attr( 'disabled' , false );  
                             },4000);
                             return  false
                         }
                         
                         $( '.icon-notice' ).removeClass( 'icon-error' ).addClass( 'icon-success' );
                         $( '.loading-mask' ).show();
                         if (f.backurl){ //如果是其他地方跳轉過來的登錄
                             location.href =  'http://' +f.backurl;
                         } else {
                             location.href =  'user.php?a=index&f=home&app=' +f.app;
                         }
                     } else {
                         $( '#fm-login-submit' ).attr( 'disabled' , false );
                     }
                 }

    主要是這一句

1
ipc.send( 'content-window-show' ,r.data);

    發送打開新窗體的命令,帶了參數r.data.

    在main.js中我們來寫監聽並響應,其實和socket.io的編寫方式差不多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//內容窗口顯示 一般登錄成功才行
var  contentWindow =  null ;
var  remindWindow =  null ;
ipc.on( 'content-window-show' , function (event,u){
     UserInfo = u;
     console.log(u);
     //先隱藏登錄窗口
     setTimeout( function (){
         mainWindow.hide(); 
     },1800);
     //創建提醒窗口
     creatRemindWindow();
     //創建內容窗口   
     if (contentWindow){
         contentWindow.focus();
         return ;
     }
     contentWindow =  new  BrowserWindow({
         frame:  false ,
         height: 700,
         resizable:  false ,
         width: 1240,
         //icon:'3.ico',
         frame:  false ,
         show:  false ,
     });
     contentWindow.loadURL(baseUrl+ 'user.php?a=index&f=home&app=1' );
     contentWindow.webContents.on(  'did-finish-load' function  () {
         contentWindow.show();
     });
     contentWindow.setSkipTaskbar( true );
     //contentWindow.webContents.openDevTools()
     contentWindow.on( 'closed' function  () {
         contentWindow =  null ;
     });
     contentWindow.webContents.on(  'new-window' function  (event,url,fname,disposition,options) {
       var  exec = require( 'child_process' ).exec; 
       //攔截url調用外部瀏覽器打開
       exec( 'start ' +url,  function (err,stdout,stderr){});
       event.preventDefault();
   });
     ipc.on( 'content-window-min' , function (){
         contentWindow.minimize();
     })
})

    我們看見了其實創建過程和創建登錄窗口差不多,通過加載不同的

1
loadURL(baseUrl+ 'user.php?a=index&f=home&app=1'

    url來顯示不同的頁面作為GUI。

    到這里,如果你能看明白,那么已經可以用electron做項目開發了,畢竟,核心的東西就這些,其他是一些小技巧,比如右下角圖標和右鍵菜單的使用,代碼如下:

    載入模塊

1
const {Menu,Tray, MenuItem} = electron;

    實現代碼

1
2
3
4
5
6
7
8
//顯示右下角圖標
   tray =  new  Tray(path.join(__dirname,  '3.ico' )) //右下角的圖標
   const contextMenu = Menu.buildFromTemplate([ //右鍵菜單項 可以是多個 這里只有關閉一個項
     {label:  '關閉' , click:  function (){
         app.quit();
     }},
     //{label: 'Item2', type: 'radio'},
   ]);

    給右下角圖標綁定右鍵菜單

1
tray.setContextMenu(contextMenu);

 綁定雙擊事件,讓其窗口顯示

1
2
3
4
5
6
7
tray.on( 'double-click' , function (){
         if (contentWindow){
             contentWindow.show();  
         } else {
             mainWindow.show();
         }
   })

    上面這些代碼需要寫在createWindow 創建登錄窗口的函數體中。

如圖:QQ截圖20160918103416.png

    如果使用右下角圖標,那么下方的任務欄不應該在顯示程序信息,隱藏方法為

1
2
//隱藏任務欄
   mainWindow.setSkipTaskbar( true );

    右鍵菜單不僅可以綁定給右下角圖標,也可以是html元素的任何位置,具體的代碼我看看 比如綁定到h1標簽上,在html中寫js代碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//右鍵菜單
const {remote} = require( 'electron' );
const {Menu,Tray, MenuItem} = remote;
 
const menu =  new  Menu();
menu.append( new  MenuItem({label:  '查看' , click() { console.log( 'item 1 clicked' ); }}));
//menu.append(new MenuItem({type: 'separator'}));
menu.append( new  MenuItem({label:  '編輯' , type:  'checkbox' , checked:  true }));
 
var  h1 = document.getElementById( 'rightButton' );
 
h1.addEventListener( 'contextmenu' , (e) => {
   e.preventDefault();
   menu.popup(remote.getCurrentWindow());
},  false );

    當然也可以在html中(非main.js)寫關閉等操作,雖然是不安全的,不推薦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const BrowserWindow = require( 'electron' ).remote.BrowserWindow
const path = require( 'path' )
 
const newWindowBtn = document.getElementById( 'openNewWindwo' )
const clo = document.getElementById( 'close' )
 
 
newWindowBtn.addEventListener( 'click' function  (event) {
   const modalPath = path.join( 'file://' , __dirname,  'modal.html' )
 
   let win =  new  BrowserWindow({id:2, width: 400, height: 320,title: 'test'  })
   
   win.loadURL(`file: //${__dirname}/model.html`)//指定渲染的頁面
   //win.show()//打開一個窗口
   //win.webContents.openDevTools()
   win.webContents.on(  'did-finish-load' function  () {
         win.show();
     });
   
   win.on( 'move' , updateReply) 
   win.on( 'resize' , updateReply)
   win.on( 'closed' function  () { win =  null  })
   
   function  updateReply () {
     const mangageWindowReply = document.getElementById( 'manage-window-reply' )
     const message = `Size: ${win.getSize()} Position: ${win.getPosition()}`
 
     mangageWindowReply.innerText = message
  
})

    在html頁面中(非main.js)枚舉所有窗體 

1
2
3
const {dialog} = require( 'electron' ).remote;
     win = BrowserWindow.getAllWindows();
     win[0]就是第一個創建的窗口

    最后介紹下文件對話框的使用 在html中寫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//打開文件框 方便讀寫文件操作
$( '#dialog' ).on( 'click' , function (e){
     const {dialog} = require( 'electron' ).remote;
     win = BrowserWindow.getAllWindows();
     dialog.showOpenDialog(win[0],{properties: [ 'openFile' 'multiSelections' ],filters: [
     //{name: 'Images', extensions: ['jpg', 'png', 'gif']},
     //{name: 'Movies', extensions: ['mkv', 'avi', 'mp4']},
     //{name: 'Custom File Type', extensions: ['as']},
     {name:  'All Files' , extensions: [ '*' ]}
   ]}, function (r){
           console.log(r);
         
       })
})

    好了,使用上大概我也就會這些,更多的操作可以去看官方英文文檔,比較詳細,希望能讓你更快的學會electron,下一篇文檔小安會抽時間做electron的打包教程,以及跨平台,其實只要打包后,下載對應的版本,跨平台修改的代碼很少,至少對我我的這個項目而言,搬運到mac系統上只刪除了幾行代碼就能運行了,祝你好運。感謝閱讀

 
 

本文來自:綿陽史安平個人博客.勵志於每一位朋友 
歡迎轉載,轉載請注明本文鏈接: electron實戰開發詳細流程 
http://www.myk3.com/arc-8856.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM