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


緣起

之前我用nwjs做過一個博客園文章編輯器的客戶端

發了好幾個版本,最后一個版本到5.0.0了

其實第一個版本已經很好了,不知足,后來自己又做了兼容markdown的,結果用來用去,發現不是自己想要的

也一直沒動手做新的,寫博客的頻率也降下去了。


最近搞了個APP(還沒上線),打算把心得寫到博客里,發現沒有趁手的編輯器

於是動手重新搞這個東西

這次用Vue+electron來搞,算是技術的主流了

先把搞這個東西的心得寫出來,希望大家不吝賜教。

界面

截幾個圖給大家看看,

列表界面:

文章編輯的界面:

功能

  • 博客登錄(引入博客園的登錄畫面,使用官方提供的登錄機制)

  • 文章列表(可以檢索到你博客園內所有的隨筆文章,支持分頁,支持文章分類)

  • 修改文章(你博客園內所有的歷史隨筆文章,都可以用此工具編輯修改)

  • 新增文章(從無到有撰寫一篇新的隨筆文章,支持保存為草稿)

  • 截圖工具截圖后直接黏貼到編輯器中(QQ截圖、微信截圖,直接黏貼到編輯器中)

  • 圖片拖拽到編輯器中自動上傳

  • 插入公式、插入地圖、插入表情、插入表格、插入音樂、插入代碼...一應俱全;

  • 純客戶端,直接與博客園服務端通信(沒有任何自建服務,不采集用戶任何信息)

  • 新版本升級提醒功能;

  • 開源,開源地址:https://gitee.com/xland/cnblogs

  • 操作系統兼容蘋果和windows,下載地址:https://gitee.com/xland/cnblogs/releases

搭建環境

這個程序用到了electron和vue

鏈接這兩個東西的橋梁是electron-vue

建議大家給個star,有這么個工具真的能省很多力氣(有錢的捧個💰場,沒錢的捧個✨場)

用npm工具初始化環境的命令為:

npm install -g vue-cli
vue init simulatedgreg/electron-vue cnblogs51
cd cnblogs51
npm install
npm run dev

幾行命令執行完,一個默認的模板畫面就啟動起來了;


我們簡單介紹一下electron-vue

我們知道vue有hot-reload的能力,

就是你改了什么代碼,馬上能在界面上表現出來,非常有利於調試;

electron-vue也有這個能力

為了做到這一點,他在你的開發機上起了http的服務;

然而你發布出來的程序,啟動的時候,並沒有在客戶機上也開一個http的服務;

也就是說,開發機上調試程序,界面訪問的是http://..........

客戶機上,運行程序界面加載的事:file://.........

工程簡述

他src目錄下,有兩個子目錄,一個是main;一個是renderer

之所以這樣分目錄,跟electron的工作原理有關系

electron與nwjs不同,

nwjs把nodejs里的v8和chrome瀏覽器里的v8整合到一起了,可以直接在網頁JS里訪問nodejs的庫

electron並沒有這么做,它分兩個主要進程,一個主進程,一個渲染進程;

對應起來就是剛才說的main目錄和renderer目錄

main目錄放主進程相關的東西

renderer目錄放界面相關的東西


如果你開發過vue的程序,你不會對renderer目錄下的東西陌生,就是一個純粹的vue項目應有的東西

main目錄下,一個index.js,一個index.dev.js

如果你的程序處於調試狀態,那么這兩個文件都會起作用(通過npm run dev命令啟動的程序);

如果你的程序處於發布狀態,那么只有index.js文件起作用(通過npm run build命令編譯打包后被安裝的程序);


如果你看了package.json文件

會發現如下配置:

"main":"./dist/electron/main.js"

這是electron程序啟動的入口,

這里的main.js就是index.js和index.dev.js合並打包出來的

注:nwjs入口程序是一個.html的文件;electron的入口程序是一個.js的文件

electron通過js入口程序加載畫面

在咱們這個工程下,他加載的事src目錄下的index.ejs畫面

這其實也是vue程序的宿主頁面


根目錄下,還有一個build子目錄,

如果沒有,你執行一下npm run build命令就有了,

你產品開發完,打包出來的東西,就放在這個目錄下;

這個目錄下,有一個icons的子目錄

打包的時候,從這個子目錄里取圖標,

打包出來的可執行文件的圖標,就是從這里得來的;


還有一個非常重要的目錄是根目錄下的static目錄

前面我們說了electron-vue開發環境和生產環境的不同;

在這個目錄里放的,就是一些靜態的資源

無論是開發環境,還是生產環境,

你只需要通過下面這樣的路徑訪問方式,就能加載到相應的資源

src="static/your/path/file.js"

程序的啟動與關閉

electron程序的入口是一個js文件

在js文件里打開一個窗口,讓這個窗口加載指定的畫面

functioncreateWindow () {
    mainWindow = newBrowserWindow({
        height:800,
        useContentSize:true,
        width:1200})
    mainWindow.loadURL(winURL)
    mainWindow.on('closed', ()=>{mainWindow =null})
}
app.on('ready', createWindow);

app在ready的時候,創建了一個窗口,並加載了一個路徑

app和窗口都是通過下面的代碼得來的:

import{ app, BrowserWindow } from 'electron'

路徑是通過下面的代碼得來的:

constwinURL = process.env.NODE_ENV === 'development'?
    `http://localhost:9080`:
    `file://${__dirname}/index.html`

electron允許打開子窗口,也允許開多標簽頁

在蘋果端,當所有窗口都關閉后,就要退出程序,代碼如下:

app.on('window-all-closed', ()=>{
    if(process.platform !== 'darwin') {
        app.quit();
    }
})

繞不開的博客園登錄

其實並不是繞不開,而是繞開的成本太高了,不值得。

就像我們做IT系統,永遠沒有一個系統是絕對安全的,

如果破壞一個系統的成本足夠高,那么我們就認為這個系統是足夠安全的;


我們想自己寫畫面,在自己的畫面上顯示博客分類、文章列表;

在自己的畫面上新建、編輯、保存文章;

這就涉及到跨域的問題

一開始我考慮,自己寫模擬登錄的代碼,登錄成功之后自己保存會話信息;

后來發現博客園還有這個東西

要想繞開這個東西,成本一下子高很多

因為這個東西的目的,就是為了防止被繞開的

(其實我有思路,但並未做嘗試)


后來想到,就算繞開又如何呢?

難道我去把博客園的服務端接口都分析一遍

真的用自己的代碼,訪問博客園的接口嗎?

我為什么不通過一個隱藏的iframe,來控制博客園的界面

通過它獲取我想呈現在自己界面上的數據;

也通過它,提交我自己界面上的用戶數據;

這樣就只要用博客園前端頁面內置的jquery獲取文章數據;

然后再用jquery操作提交、草稿按鈕就可以了。


在nwjs環境里,我們真的就是用的一個iframe,代碼如下:

var iframeTag = 'nwUserAgent="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.3538.400 QQBrowser/9.6.12501.400"';
var articleDiv = '<iframe id="articleFrame" src="[your url]" nwdisable nwfaketop '+bky.iframeTag+'></iframe>';

這里涉及到三個特殊的屬性

  • nwdisable:

是為了防止這個iframe加載的頁面去調用nwjs的一些功能,比如說格盤,因為畢竟我們加載的頁面不是我們自己提供的,要為我們用戶的安全着想;

  • nwfaketop:

如果沒有這個,在iframe頁面里調用window.top,就能訪問到我們的頁面的window對象,很多廠商都是通過這個來判斷自己是不是被別人iframe了,有了這個標簽,window.top就訪問不到我們

  • nwUserAgent:

我們通過這個標簽來設置iframe加載頁面時使用的user-agent,進一步隱藏自己,不被服務提供方發現;


在electron里,不是直接用iframe,而是用了electron內置的一個webview的標簽

<webview ref="frame" :preload="preloadJsPath" :src="enterUrl" :useragent="$root.agent"></webview>

(注意:上面這行代碼用到了vue的一些特性)

它也有useragent屬性,跟nwjs里的nwUserAgent一樣

它默認就是不允許被加載頁面訪問electron的底層API的,

因為根本就不是iframe,所以window.top也訪問不到它的宿主頁面;


我的目的是讓我的用戶使用我開發的畫面

我的客戶在不需要的時候,不需要看到博客園的任何界面

所以這個webview默認是隱藏的;


在用戶第一次打開應用的時候,這個webview會直接加載博客園后台的頁面:

enterUrl:"https://i.cnblogs.com/posts"

如果你第一次使用這個應用,你本地肯定沒有會話信息,所以你訪問后台頁面,博客園會給你跳轉到登錄頁面;

我們可以在webview的dom-ready事件里監控webview內部的url變化,代碼如下:

var self = this;
var frame = this.$refs.frame;
frame.addEventListener("dom-ready",function(e){
    if(frame.src.search('https://passport.cnblogs.com/user/signin') == 0) {
        frame.style.zIndex ="99";
    }else{
        frame.style.zIndex = "1";
        //other code...
    }
});

當url變成登錄頁面時,我們就讓webview顯示出來,

這時我們的應用跟一個普通的瀏覽器沒有任何區別,

我們的客戶也是在與博客園的登錄頁面交互,

當用戶登錄成功之后,url又會變成https://i.cnblogs.com/posts,

此時,我又讓webview隱藏起來,把我自己的界面呈現給用戶

這個時候用戶已經登錄成功了

雖然我自己的界面還是沒有博客園的會話信息

但是這個webview已經具備了合法的身份

可以隨意訪問博客園后台的任意API

接下來,我們的界面就會以這個webview為橋梁,與博客園后台服務進行交互。

小結

想通了這些,我發現我手里多了一把錘子🔨

有很多事情可以做呀

寫個自動下單工具、秒殺工具、搶票工具之類的,都是易如反掌;

不會在糾結怎么模擬登陸,就算真要模擬登陸,也不是完全沒辦法;

因為在這個環境下,目標網站的前端代碼,完全暴露在你眼前,隨你想怎么控制就怎么控制

具體怎么搞,我們一下篇再說

,有着急的朋友,可以先看我開源出來的代碼

不過,我想要做的就是讓這個工具兼容更多的博客

現在博客園已經做差不多了,接下來兼容什么呢?CSDN?知乎?簡書?segmentfault?歡迎大家留言;

另外,安裝程序的下載地址為:https://gitee.com/xland/cnblogs/releases

大家發現什么問題可以直接提issue,如果大家期待什么新功能,也可以提issue(qq群:51021155)

喜歡的朋友,請幫忙點個贊,給個星






免責聲明!

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



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