UEditor 之初體驗後記

来源:https://www.cnblogs.com/hanzongze/archive/2019/07/18/js-ueditor.html
-Advertisement-
Play Games

UEditor 的核心特點就是:產自大廠、開源免費、功能全面(相當全)、體驗較為切合國人習慣。只需要修改相應的後端代碼,即可把 UEditor/UMeditor 中的圖片上傳到諸如又拍雲 USS 或阿裡雲 OSS 等雲存儲伺服器上,既安全又經濟。 ...


本文初稿寫於 3 年前,近期重新編輯整理,併進一步完善補充而成。

1、UEditor 基本介紹

1.1、關於 UEditor

UEditor是由百度web前端研發部開發所見即所得富文本web編輯器,具有輕量,可定製,註重用戶體驗等特點,開源基於MIT協議,允許自由使用和修改代碼。

上面這句話出自 UEditor 官方。在我看來,UEditor 的核心特點就是:產自大廠、開源免費、功能全面(相當全)、體驗較為切合國人習慣。想瞭解 UEditor 的更多信息,可參考以下幾個鏈接:

另外,UEditor 官方還提供了一個 Mini 版,名字叫 UMeditor。說是為了滿足廣大門戶網站對於簡單發帖框,或者回覆框需求所定製的版本。主要改進點在載入速度和載入失敗率上,且功能與 UEditor 也略有不同,具體可參考 UMeditor 的 GitHub

1.2、UEditor 現狀

UEditor 的最新版本是 v1.4.3.3,UMEditor 的最新版本是 v1.2.3。最後一次發佈都在 2016 年下半年,都快 3 年沒更新了。不過基本功能該有的也都有,且社區也比較認同和推崇,有不少人或組織都提供了特色的改進版或增強版,官方也偶有跟進。

綜合來看,目前要在國內做相對複雜的資訊發佈或留言功能,UEditor/UMEditor 依然是最好的選擇之一。

2、UEditor 簡單使用

2.1、將 UEditor 源碼集成到項目中

如果你要在後端項目中集成 UEditor,那麼直接下載對應語言版本的源碼,解壓之後拷貝到項目中即可。有兩點需要註意:

  • 1、官方只提供了 PHP、ASP、ASP.NET、JSP 四個版本,社區里有人提供了 Note.js、Python 等語言的版本。
  • 2、官方說提供的所有後端代碼都僅為 DEMO 作用,切不可直接用到生產環境中。平心而論,ASP.NET 版的後端代碼寫的確實水,不過前端能寫出這些後端代碼就已經很牛掰了,我是把用到的那部分代碼從頭到尾改了一遍才用到生產環境中的。

如果你要在前端項目中集成 UEditor,那就看你需不需要上傳圖片等後端功能了。如果不需要,那麼直接拷貝到前端項目中即可。但如果需要,那就得確保跑前端的 Web 伺服器能解析對應的後端代碼了。

當然,如果你把 UEditor 單獨部署到一個支持後端的 Web 伺服器上也是可行的。另外,集成 UMeditor 的方法與集成 UEditor 方法完全一樣。

2.2、讓 UEditor 的 UI 呈現在頁面中

1、首先,需要在頁面中引入 UEditor 的 3 個 js 文件,示例如下:

<!-- 編輯器的配置文件,前端配置都在這個文件中,註釋十分豐富 -->
<script type="text/javascript" charset="utf-8" src="/ueditor-1.4.3/ueditor.config.js"></script>
<!-- 編輯器的源碼文件 -->
<script type="text/javascript" charset="utf-8" src="/ueditor-1.4.3/ueditor.all.min.js"></script>
<!-- 編輯器的中文語言包 -->
<script type="text/javascript" charset="utf-8" src="/ueditor-1.4.3/lang/zh-cn/zh-cn.js"></script>

2、然後,在頁面中需要呈現 UEditor 的地方放置如下“占位符”代碼(註意給個 ID,下一步要用):

<!-- 編輯器的容器 -->
<script id="editor" type="text/plain" style="width:800px; height:300px;"></script>

3、最後,通過一句實例化編輯器的代碼來獲得編輯器實例(頁面運行起來時 UI 就會呈現出來):

$(function () {
    var ue = UE.getEditor("editor"); // 創建編輯器實例(這裡的 editor 就是上一步中的 ID)
});

得到編輯器實例對象之後,就可以通過它來調用 UEditor 的哪些 API 了。具體有哪些 API 可用,參見 UEditor API

2.3、用 UEditor 的過程中遇到的兩個坑

1、坑一,獲取內容可以而設置內容卻報錯

我用getContent獲取編輯器的內容並存入資料庫,然後把存到資料庫中的內容用setContent賦給編輯器。結果運行起來發現保存入庫可以,而打開編輯頁面直接就報錯了,編輯器也沒顯示出來。

後來發現這個是因為編輯器還沒準備好,所以就不能賦值,只需要把賦值操作放到ready之後即可,示例代碼如下:

ue.addListener("ready", function () {
    ue.setContent("@Model.Content"); // 等編輯器準備好之後再賦值,否則報錯
});

為了寫這篇文章,我嘗試了重現那個錯誤,結果編輯器又顯示出來了,但依然會報錯,錯誤消息是“Uncaught TypeError: Cannot set property 'innerHTML' of undefined”。

從某種程度上說,這個問題並不算是坑。因為官方手冊中就有相關說明和建議——“對編輯器的操作最好在編輯器ready之後再做”,不過我這人特別怕麻煩,凡是能憑猜測搞定的就不願細看文檔,所以第一次用的時候就掉坑了。

2、坑二,編輯器內顯示的是的 HTML,而不是文本內容

一開始還懷疑這會不會是 UEditor 的 Bug,直到把這個問題解決之後,反過來想才發現這裡面其實隱含了一個容易被忽略的“常識”,那就是網頁的模版引擎一般都會編碼字元串,比如我曾用過的 WebForms、NVelocity 和 RazorEngine 都是這樣。

換句話說,這時候編輯器拿到的是經過編碼之後 HTML,也就是說只要我們能確保編輯器拿到的是編碼前的 HTML 就行了。當然一開始我還沒想到是這個原因,於是我的解決辦法是根據曾使用其它編輯器的經驗試出來的,就是直接把內容放到script標簽中,示例代碼如下:

<script id="editor" type="text/plain" style="width:800px;height:300px;">
    @WebTools.RazorHelper.Raw(Model.Segment.Note)
</script>

在我意識到這個問題的始作俑者是網頁模版引擎而不是 UEditor 的時候,我做瞭如下測試:

ue.addListener("ready", function () {
    editor.setContent("@WebTools.RazorHelper.Raw(Model.Segment.Note)");
});

果然也是 OK 的,這也進一步證明瞭我的猜想是正確的!

2.4、將 UEditor 中的圖片上傳到雲伺服器上

由於 UEditor 預設是將圖片上傳到網站根目錄下的一個子文件夾中,如果是企業內部的信息系統,這麼做也還行,但如果是互聯網項目,這種做法就顯得既不安全、也不經濟的了,最好還是上傳到雲伺服器上。

要把 UEditor 中的圖片上傳到雲伺服器上,只需要修改後端代碼的上傳邏輯即可。我做過用 ASP.NET 把 UEditor 1.4.3 中的圖片上傳到 又拍雲 USS 和把 UMeditor 1.2.2 中的圖片上傳到 阿裡雲 OSS,其實思路是一樣的。

UEditor 的 ASP.NET 核心上傳邏輯在UploadHandler類的Process方法中,將上傳圖片到本地的那部分代碼替換成如下示例代碼即可。

try {
    // 校驗文件類型、文件大小等......
    String fileMd5 = StringSecurity.GetMd5(uploadFileBytes); // 用文件的 MD5 值做文件名
    String fileName = fileMd5 + Path.GetExtension(uploadFileName);
    String filePath = $"/images/{DateTime.Now.ToString("yyMMdd")}/{fileName}";
    // 調用又拍雲的 SDK 來上傳文件
    UpYun upyun = new UpYun("bucketname", "username", "password");
    upyun.setContentMD5(fileMd5);
    bool upyunResult = upyun.writeFile(filePath, uploadFileBytes, true);
    // ......
} catch (Exception e) {
    logger.Error("文件上傳失敗!", e);
    // ......
}

UMeditor 的 ASP.NET 核心上傳邏輯在Uploader類的upFile方法中,將上傳圖片到本地的那部分代碼替換成如下示例代碼即可。

try {
    // 校驗文件類型、文件大小等......
    String fileName = $"{GuidHelper.LowerPureString}.{getFileExt()}";
    String filePath = $"images/{DateTime.Now.ToString("yyMMdd")}/{fileName}";
    // 調用阿裡雲的 SDK 來上傳文件
    var client = new OssClient(SrcPoint, AccessKeyId, AccessKeySecret, 
        new Aliyun.OSS.Common.ClientConfiguration() { IsCname = true });
    var putResult = client.PutObject(SrcBucket, filePath, uploadFile.InputStream);
    // ......
    var uri = client.GeneratePresignedUri(SrcBucket, filePath);
    URL = uri.GetLeftPart(UriPartial.Path); // 將文件路徑賦值給編輯器引用的變數
} catch (Exception e) {
    logger.Error("文件上傳失敗!", e);
    // ......
}

可能你看到本文時,又拍雲和阿裡雲的雲存儲 SDK 已經做了較大改動,這裡附上二者的 GitHub 鏈接:

3、Web 編輯器雜談

3.1、我與 UEditor 的曲折歷程

2016 年初,我基於學習的目的,業餘做了一個帶新聞發佈功能的網站。在這之前,我曾先後用過 FreeTextBoxFCKeditor(已更名為 CKEditor),印象中都還不錯,但也都有著這樣或者那樣的問題,比如 CKEditor 中空格變問號的問題

我上網搜了一下,發現大家對 UEditor 的評價還不錯,於是決定 Web 編輯器就用 UEditor,由於是第一次用,過程相對曲折。做完新聞發佈功能之後,就順帶記錄了一下,也就是本文初稿。

兩年之後,也就是去年,公司要做個帶資訊發佈功能的媒體網站,在我的建議下,最終選用了 UMeditor。但整個團隊除我之外都沒用過,尤其是那幾個前端,連富文本編輯器是啥都不知道,最後就由我負責帶領前端來做這塊兒的功能。

因為這次做的是實際項目,公司的編輯們都在用,後臺的 UI 框架也由 jQuery 版的 EasyUI 變成了 React 版的 Ant Design,所以遇到的細節問題也比較多。其中對編輯器的各種配置和後端改造,都是由我統一解決好再跟前端對接的。

又過了一年,也就是本月初,我在整理資料時再次看到了本文初稿。瞬間就想起我去年用 UMeditor 的過程中也做過一些記錄,然後就想著乾脆把兩次的記錄整合起來,結果怎麼都找不到去年的記錄,只好作罷。也許還留在那家公司的電腦里吧!

3.2、CKEditor 空格變問號的原因及解決辦法

經查,導致該問題的根本原因是編碼轉換。在 UTF-8 里有一個特殊的編碼0xC2 0xA0,轉換成字元的時候,表現為一個空格,跟普通的半形空格一樣,不同的是它的寬度不會被壓縮,因此常被用來做網頁排版。而在 GB2312、Unicode 等字元集中卻沒有這個編碼,因此如果簡單地進行編碼轉換,這個編碼就會被替換成問號。

前些年在實際項目中還遇到過更奇葩的情況,文章保存之後,內容中的問號就全都沒了。後來發現是別人也遇到了空格變問號的問題,但選錯瞭解決方案,他是直接把問號又替換成空格,結果正常的問號也被斃掉了。

正確的做法是,用 UTF-8 格式的編碼進行替換,把那個特殊的空格替換為普通的空格,如果是 HTML 字元串,那就替換為&nbsp;。C# 代碼替換 HTML 字元串的示例如下:

byte[] space = new byte[]{0xc2,0xa0};
string utfSpace = Encoding.GetEncoding("UTF-8").GetString(space);
htmlStr = htmlStr.Replace(utfSpace,"&nbsp;");

註意:在替換之前不能進行編碼轉換,一定要繼續使用 UTF-8 編碼。如果已經轉換成其它編碼,那就徹底沒救了,因為這時候錯誤的問號和正常的問號之間已經沒有分別了。

本文鏈接http://www.cnblogs.com/hanzongze/p/js-ueditor.html
版權聲明:本文為博客園博主 韓宗澤 原創,作者保留署名權!歡迎通過轉載、演繹或其它傳播方式來使用本文,但必須在明顯位置給出作者署名和本文鏈接!個人博客,能力有限,若有不當之處,敬請批評指正,謝謝!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 列表是一個可以修改的,元素以逗號分割,用中括弧包圍的有序序列 格式:變數名 = [元素1,元素2,元素3,...] 列表序列操作: 1.相加: 2.重覆: 3.索引: 4.修改: 列表方法: 1.增加操作: append:追加,在列表尾部加入指定元素 append方法直接在原列表上做修改,返回值是N ...
  • 第九章併發編程 同一個程式執行多次是多個進程 9.1 開啟子進程的兩種方式 服務端目標: 1、不間斷地提供服務 2、服務端要支持高併發+高性能 一個進程在運行過程中開啟了子進程(如nginx開啟多進程,os.fork,subprocess.Popen等) 父進程發起請求,操作系統創建子進程 方式一: ...
  • 平面上有若幹個矩形,求矩形相互覆蓋的面積。為方便起見,矩形的邊均平行於坐標軸。 我們根據容斥原理,矩形相互覆蓋的面積即為所有矩形的面積和減去所有矩形所覆蓋的面積即可。 而現在問題是如何求得所有矩形所覆蓋的面積。即 讓我們人類去做,由於這是個由矩形拼接成的多邊形,很難去直接求它的面積,求該圖形的面積一 ...
  • 1.見名知意 起一個有意義的名字,儘量做到看一眼就知道是什麼意思 2.下劃線命名法 所有單詞小寫,單詞間用_連接 用於變數、函數的命名 3.大駝峰命名法 每個單詞直接連接,每個單詞首字母大寫 用於類的命名 補充: 1.以單_開頭的變數名_x不會被from module import * 語句導入 2 ...
  • x86 64數據格式、通用寄存器與操作數格式 數據格式 ​ Intel用術語“字(word)”表示16位數據類型,32位為“雙字(double words)”,64位數為“四字(quad words)”。 | C聲明 | Intel數據類型 | 彙編代碼尾碼 | 大小(位元組) | | : : | : ...
  • C++中經常會用到標準庫函數庫(STL)的string字元串類,跟其他語言的字元串類相比有所缺陷。這裡就分享下我經常用到的兩個字元串截斷函數: include include include include using namespace std; //根據字元切分string,相容最前最後存在字元 ...
  • 上次給大家分享了小白建站如何選擇虛擬空間及伺服器,及購買功能變數名稱的基礎知識,這些是硬性要求,你的網站要想運行起來,硬體只是基礎,真正的技術是軟體,關於PHP軟體開發技術,後面我們會慢慢的分享給大家,今天主要給大家分享的是,如何在你伺服器配置PHP運行的環境,有哪種模式,如何選擇呢? ...
  • C#是跟著楊老師的教程走的,在這裡感謝一下老師的無私奉獻,他的cnblog地址:>cgzl,他的B站地址:>solenovex。 進入正題: Delegate表示委托,委托是一種數據結構,它引用靜態方法或引用類實例及該類的實例方法。(引用官方文檔的英文原話) Represents a delegat ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...