自己動手用electron+vue開發博客園文章編輯器客戶端【二】


回顧

上一篇文章中,

咱們聊了我開發的這個程序是什么樣子、為什么要開發這個程序

electron的工程結構,他是怎么啟動和退出的

以及我們怎么用electron的技術,登錄博客園,拿到會話信息;

這篇文章,我們主要講怎么拿博客園的數據,以及怎么提交數據給博客園;

上幾張新圖:

宿主畫面與webview通信的問題 

在nwjs里,宿主頁面與做過特殊標記的iframe頁面(nwdisable nwfaketop和nwUserAgent)通信,並沒有什么特別的地方

就像你在一個普通的頁面里訪問你自己的iframe子頁面一樣

var frame = document.getElementById('[yourFrameId]').contentWindow;

可以通過上面的代碼,輕而易舉的得到iframe頁面的window對象;

注意:被標記了nwfaketop的子頁面里的代碼是訪問不到父頁面的window對象的;

 

然而在electron里,宿主頁面要想跟webview頁面通信的話,事情就復雜的多了

你要給webview頁面配置preload屬性,

讓webview把你一個你自己寫的JS文件注入到目標頁面里去,如下:

<webview preload="[your js file path]" src="http://[yourTargetUrl]"></webview>

你可以在這個JS文件里訪問目標頁面上任何東西,就像你自己寫了一個JS文件放在目標網站里一樣;

不僅如此,你還可以在這個JS文件里訪問electron提供的底層API;

 

然而怎么把訪問到的東西呈現在自己的畫面上呢

比如,我們在這個JS文件里拿到了博客分類的數據:

var temp = $("#post_categories a[href^='/posts?categoryid=']");

注:博客園是我們的目標網站,目標網站加載了jquery,我們這個注入的js也可以使用jquery的能力

再通過如下代碼反饋給我們自己的畫面

const {ipcRenderer} = require('electron')
ipcRenderer.sendToHost('messageFromWeb', temp);

ipcRenderer就是electron里的東西了,

看這個API就知道,這是在通過消息的方式通信,

我們需要在自己的畫面里監聽這個消息

var webViewInstance = document.getElementById('[yourWebViewId]');
webViewInstance.addEventListener("ipc-message", event=>{
    console.log(event.args[0]);
}

這里event.args[0]就是注入JS里傳過來的temp對象,也就是博客分類的數據了

接下來,就想怎么呈現就怎么呈現。

 

如果想把自己畫面里的數據傳遞給注入的JS代碼

需要在自己畫面發送消息,代碼如下:

var webViewInstance = document.getElementById('[yourWebViewId]');
webViewInstance.send("messageFromHost","hookSaveArticle",{data:'your article data'});

在注入的JS代碼里,可以通過下面的代碼來獲取宿主頁面發送過來的消息:

const {ipcRenderer} = require('electron')
ipcRenderer.on('messageFromHost', (event, action, obj)=>{
    console.log(action);  //print hookSaveArticle
    console.log(obj);  //print {data:'your article data'}
})

以上,

我們現在可以自由的在目標頁面和宿主頁面互相通信,傳遞數據了;

但是!

File類型和Blob類型的數據不能這樣傳遞,這是官網文檔里並沒有說明的,是我自己踩坑踩出來的

那么這樣的數據該怎么發送呢?

我是先在發送方轉成base64,再在接收方轉回來達到目的的

雖然有點脫了褲子放屁,但是聊勝於無呀!

發送方的代碼如下:

window.editorUpload = function(file) {
    var reader = newFileReader();
    reader.readAsDataURL(file);
    reader.onload = function() {
        webViewInstance.send("messageFromHost","hookUploadPic", {base64:reader.result,
            name:file.name});
    };
}

接收方的代碼如下:

functiondataURLtoFile(dataurl, filename) {
    var arr = dataurl.split(','),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]),
    n = bstr.length,
    u8arr = newUint8Array(n);
    while(n--) { u8arr[n] = bstr.charCodeAt(n); }
    return newFile([u8arr], filename, {type: mime});
}
ipcRenderer.on('messageFromHost', (event, action, param)=>{
    var file = dataURLtoFile(param.base64, param.name);
})

與編輯器相關的問題

我們用的是NEditor編輯器,前身是百度的UEditor編輯器,不過百度的UEditor已經不再維護了

然而,就算NEditor編輯器,我也修改了里面很多東西

上傳文件,我們上一個章節說過了,不得不修改,

因為我們要把用戶貼過來的圖片發送給鈎子JS,而不是直接upload到自己的服務器上;

我大概在neditor.all.js的26616行,加了一行自己的代碼,大家可以去看我的源碼

以后打算讓這個編輯器方便的兼容base64,這樣就不用事先把圖片傳博客園服務器上去了,不知道這個思路靠譜不靠譜;

 

另外,因為編輯器相關的前端文件都是靜態資源,我就把他們放到static目錄下去了

這樣只要在主頁直接把這些靜態資源加載過來就可以了

<script src="static/editor/neditor/neditor.config.js"></script>
<script src="static/editor/neditor/neditor.all.js"></script>
<script src="static/editor/neditor/neditor.service.js"></script>
<script src="static/editor/neditor/i18n/zh-cn/zh-cn.js"></script>

其他的一些樣式文件,ueditor自己會自動加載,路徑也不會有什么問題

多標簽頁的問題

在我上一個版本的程序里,一次只能編輯一篇文章

有人反映說,這樣不是很方便,於是這個版本做了多標簽頁的功能;

首先,我用一個數組存儲每個標簽頁的基礎數據

tabs: [{text:"文章列表",
    url:"https://i.cnblogs.com/posts",
    isHomePage:true,
    pageType:'list',
    data:null
}],

vue的模板代碼里呈現這個數組的數據:

<div @click="selectTab(index)" v-for="(tab,index) in tabs">

程序剛啟動的時候,就這么一個標簽頁,當用戶點了文章列表的某條文章的時候,執行下面的方法

articleClick(url, text) {
    var obj = {url,text,"pageType":"editor",data:null};
    this.tabs.push(tab);
    this.webViewInstance.loadURL(url);
}

這樣就多了一個標簽頁;

因為我們這個程序,只有兩種類型的畫面,不是文章列表,就是編輯文章(添加文章和編輯文章是同樣的畫面)

所以,雖然是多個標簽頁,也不過是在這兩種畫面間切換

vue的模板代碼如下

<div class="main">
    <list v-show="tabs[tabsSelectedIndex].pageType == 'list'"></list>
    <editor v-show="tabs[tabsSelectedIndex].pageType == 'editor'"></editor>
</div>

根據當前tab頁的類型,切換畫面;

每次新tab頁的加入,我們就迫使webViewInstanceload一下tab對應的url,以拿到目標頁的數據;

每次tab頁的切換,我們就從tab數組元素里拿data數據,其實就相當於我們緩存的數據(並沒有存成本地文件或本地數據庫呢);

由於UEditor不是一個VUE組件,所以我們在切換頁面,新加頁面的時候,要通過UEditor的API獲取數據,重置數據,代碼如下:

UE.instants.ueditorInstant0.getContent();
UE.instants.ueditorInstant0.setContent(content);

總結

寫到這里,發現並沒有什么特殊的東西需要在博客里解釋了

還有不明白的地方的讀者,自己去看源碼吧!

下載地址:www.xiangxuema.com

謝謝大家的支持;

 

接下來我打算為這個程序加入下面這些功能:

  • 刪除文章

  • 編輯分類

  • 支持CSDN博客

  • 支持開源中國博客

  • 支持簡書

  • 支持知乎

  • ......

請大家多多關注:https://github.com/xland/xiangxuema

 


免責聲明!

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



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