使用electron和vue,以ipc通訊的方式構建客戶端版本的掘金首頁

feng-fu發表於2018-01-31

1. 使用electron-vue新建基於vueelectron環境,更多配置請訪問源專案

npm i -g vue-cli
vue init simulatedgreg/electron-vue my-project
cd my-project
npm i
npm run dev
複製程式碼

2. 打通electron主程式與渲染程式的通訊

定義常量作為channel,也就是事件型別名稱

const CLIENT_NORMAL_MSG = 'CLIENT_NORMAL_MSG'  // 渲染程式發出訊息型別
const CRAWLER_NORMAL_MSG = 'CRAWLER_NORMAL_MSG' // 主程式發出訊息型別
複製程式碼
渲染程式

在渲染程式中,使用vue plugin的形式,具體參見vue官方文件外掛

ipcRenderereventEmitter的一個例項,在渲染程式中使用,你可以通過它來像主程式傳送同步和非同步訊息,也可以通過它來接收來自主程式的訊息

  const { ipcRenderer } = require('electron')
  const ipcService = Object.create(null)
  const callbackCache = []

  ipcService.install = Vue => {
    Vue.prototype.$ipcRenderer = {
      send: (msgType, msgData) => {
        ipcRenderer.send(CLIENT_NORMAL_MSG, {
          type: msgType,
          data: msgData,
        })
      },
      on: (type, callback) => {
        callbackCache.push({
          type,
          callback,
        })
      }
    }
    ipcRenderer.on(CRAWLER_NORMAL_MSG, (sender, msg) => {
      callbackCache.forEach(cache => {
        if (cache.type === msg.type) {
          cache.callback && cache.callback(msg.data)
        }
      })
    }) // 監聽主程式的訊息
  }

  export default ipcService

複製程式碼

vue專案中通過this.$ipcRenderer.on的方式新增主程式傳送訊息的監聽,通過this.$ipcRenderer.send的方式向主程式傳送訊息,保證發出訊息均為CLIENT_NORMAL_MSG型別,收到訊息均為CRAWLER_NORMAL_MSG,通過訊息中的二級固定引數type來區分具體型別,並可以通過detach的方式來取消特定的型別的訊息的監聽

最後在Vue的入口檔案,也就是渲染程式的入口檔案使用上面定義的外掛 Vue.use(ipcService) 渲染程式中的配置完成


主程式

使用class的方式來定義,需要傳入兩個引數來例項化這個class,需要傳入兩個引數,listener為監聽訊息者,sender為傳送訊息者

ipcMsgHandler中包含了所有的handler,為其傳入this以便能夠在其中向渲染程式傳送訊息

  import ipcMsgHandler from './ipcMsgHandler'

  export default class Ipc {
    constructor(listener, sender) {
      this.listener = listener
      this.sender = sender
      this.addListener(CLIENT_NORMAL_MSG, this.handleFn.bind(this))
      this.handlerList = ipcMsgHandler(this)
    }

    handleFn(event, data) {
      try {
        this.handlerList[data.type](event, data.data)
      } catch (error) {
        console.error('handler event error:' + error.message)
      }
    }

    addListener(chanel, cb) {
      this.listener.on(chanel, cb)
    }


    _sendMsg(chanel, msgBody) {
      this.sender.send(chanel, msgBody)
    }

    sendToClient(type, data) {
      this._sendMsg(CRAWLER_NORMAL_MSG, {
        type,
        data,
      })
    }
  }
複製程式碼

初始狀態下ipcMsgHandler.js檔案

export default _ipc => ({})
複製程式碼

在主程式的入口檔案(/src/main/index.js)中對Ipc這個class例項化,其中需要使用的listeneripcMainipcMainipcRenderer不同,它只負責對訊息的監聽,不復雜傳送訊息,這裡需要入口檔案中的mainWindow下的webContents作為訊息的傳送者,所以需要在mainWindow建立成功之後再進行Ipc的例項化

// ...
function createWindow() {
  mainWindow = new BrowserWindow({
    // ...
  });
  new IpcMgr(ipcMain, mainWindow.webContents)
}
複製程式碼

3. 完成具體功能開發

引入element-ui,使用babel配置css按需載入,具體配置方式element-ui官網

分析掘金首頁資料來源

掘金首頁七種分類下資料均來自一個介面,https://timeline-merger-ms.juejin.im/v1/get_entry_by_rank?src=web&limit=20&category=xxx,通過category進行分類的區分

渲染程式開發

App.js中,在進入頁面和切換分類時向主程式傳送訊息

// ...
  methods: {
    startRequest() {
      this.$ipcRenderer.send('start-request', this.activeCategory)
    },
    onRequestBack() {
      this.$ipcRenderer.on('request-back', data => {
        // todo...
      })
    },
  }
複製程式碼

主程式開發

現在渲染程式中已經定義了兩種訊息型別start-requestrequest-backstart-request告訴主程式開始執行任務,完成後request-back告訴渲染程式任務完成,渲染程式收到訊息後通過收到的資料來對頁面進行操作。

ipcMsgHandler.js中進行擴充,使用axios對介面內容進行抓取

  import axios from 'axios'
  const handlerList = _ipc => ({
    ['start-request'](event, category) {
      const requestBack = data => {
        _ipc.sendToClient('request-back', data)
      }
      axios.get(`https://timeline-merger-ms.juejin.im/v1/get_entry_by_rank?src=web&limit=20&category=${category}`)
        .then(r => {
          if(r.status === 200) {
            requestBack({
              success: true,
              rows: r.data.d.entrylist
            })
          } else {
            requestBack({
              success: false,
              error: `server error code: ${r.status}`
            })
          }
        })
        .catch(e => requestBack({
          success: false,
          error: `server error code: ${e.status} msg: ${e.message}`
        }))
    }
  })
複製程式碼

請求完成後,通過requestBack向渲染程式傳送訊息,渲染頁面,操作樣式調整,頁面看起來大概是這樣。

使用electron和vue,以ipc通訊的方式構建客戶端版本的掘金首頁

4. 增加連結跳轉到預設瀏覽器

在該專案中如果直接使用window.open的方式來開啟的話,它會新彈出一個electron視窗,所有連線跳轉也需要用到ipc的方式

electron中,有一個shell物件,它提供一個openExternal的方法來在預設瀏覽器中開啟連結

ipcMsgHandler.js中新增以下內容

  const { shell } = require('electron')
  export default _ipc => ({
    ['open-shell'](event, url) {
      shell.openExternal(url)
    },
    // ...
  })
複製程式碼

現在就可以在vue中通過this.$ipcRenderer.send('open-shell', url)的方式來在預設瀏覽器中開啟連結了

一個通過打通IPC通訊方式的掘金首頁概覽客戶端就完成了,通過npm run build就可以對這個應用進行打包了

PS: 其實在electron中是可以支援跨域訪問的,只需要在建立視窗的時候加上一下配置項就行了,不過結果其實並不重要,重要的是過程了

webPreferences: {
  webSecurity: false,
}
複製程式碼

以上程式碼都可以在github上找到,歡迎star~~~

相關文章