[譯] 通過 contentEditable 屬性創建一個所見即所得的編輯器(富文本編輯器)


譯者注

這只是一篇入門教程,介紹了一些基礎知識,僅供參考,切不可因此覺得富文本編輯器很簡單。

創建富文本編輯器是一個非常復雜的工程,需要考慮到方方面面,也有很多坑(請參考原文第一條評論)。

為免誤導大家,特此說明。

 

格式說明:鏈接名詞命令

 


原文:Create a WYSIWYG Editor With the contentEditable Attribute

 

WYSIWYG 編輯器非常常用,你或許在某個時候也使用過。

WYSIWYG:What You See Is What You Get,所見即所得。

通過一些第三方庫,你可以快速地創建自己的編輯器,但也有一些明顯的缺陷。首先,它們很重,許多特性你壓根就用不到。另外,定制外觀也非常蛋疼。

本文中,我們將按自己喜歡的風格,創建一個擁有基本格式化功能的、輕量的所見即所得編輯器。

我們將從介紹 execCommand 開始,因為在實現編輯器的過程中,我們會大量使用到該方法。

 

Document.execCommand()

execCommand 是 document 對象的一個方法,它提供了操作可編輯區域的內容的能力,和 contentEditable 配合使用,就可以實現一個富文本編輯器(rich-text editor)。

execCommand 方法可以進行各種編輯操作,如 添加鏈接、選中文本 加粗 或 斜體,修改 字體字體顏色,使用語法如下:

document.execCommand(CommandName, ShowDefaultUI, ValueArgument);

CommandName:DOMString,指定所要執行的命令。

ShowDefaultUI:Boolean,指定是否顯示用戶界面,該選項還未完全實現,一般設置為 false。

ValueArgument:提供命令的附加參數,如圖片URL或顏色值。不需要附加參數時,設置為 null。

我們將使用不同的命令來實現各種功能,下面逐一介紹。

 

無附加參數的命令

部分命令不需要附加參數(ValueArgument),如加粗(bold)、對齊(justify)、撤銷(undo)、重做(redo),使用下面的語法:

document.execCommand(commandName, false, null);

CommandName 為命令名,如 justifyCenterjustifyRightbold 等。

 

帶附加參數的命令

部分命令需要傳入相應的附加參數,如插入圖片(insertImage)、創建鏈接(createLink)、字體顏色(foreColor),使用下面的語法:

document.execCommand(commandName, false, value);

commandName insertImage 時,value 為將要插入的圖片的 URL。

commandName foreColor 時,value 為顏色值字符串,如 #FF9966、blue。

 

添加塊樣式標簽的命令

添加 HTML 塊樣式標簽(Block-Style Tags),需要將 commandName 指定為 formatBlockValueArgument 設置為標簽名(tag name),使用下面的語法:

document.execCommand('formatBlock', false, tagName);

該命令將為當前選中行添加一個 HTML 塊樣式標簽,如果本身已帶有標簽,則將被替換掉。

tagName 為塊樣式標簽名,如標題標簽(h1-h6)、段落標簽(p)或塊引用(blockquote)。

 

上面是一些最常用的命令,更多信息請參考 document.execCommand API 文檔,那里有所有可用命令的列表。

 

創建一個工具欄

了解了基礎知識,下面我們來創建一個工具欄,工具欄的按鈕我使用了 Font Awesome 圖標。

大家可能也注意到了,除了少數區別,所有的 execCommand 命令都有類似的結構,基於這個特點,我們可以使用下面的節點結構來定義工具欄的按鈕:

<a href="#" data-command='commandName'><i class='fa fa-icon'></i></a>

通過這種方式,當用戶點擊按鈕時,我們可以從 data-command 屬性中獲取到 execCommand 所要執行的命令。

例如下面這些例子:

<a href="#" data-command='h2'>H2</a>
<a href="#" data-command='undo'><i class='fa fa-undo'></i></a>
<a href="#" data-command='createlink'><i class='fa fa-link'></i></a>
<a href="#" data-command='justifyLeft'><i class='fa fa-align-left'></i></a>
<a href="#" data-command='superscript'><i class='fa fa-superscript'></i></a>

第一個按鈕的 data-command 屬性值為 h2,在 JavaScript 中獲取到這個值后,我們將使用 execCommand 方法的 添加塊樣式標簽的命令。同樣的,最后一個按鈕,superscript 則表示應該使用 無附加參數的命令

創建字體顏色(foreColor)和背景顏色(backColor)按鈕則是另外一種實現方法,這里主要有兩個問題。

第一個問題是,提供給用戶選擇的顏色越多,需要編寫的代碼就越多,很麻煩而且容易出錯。可以使用下面的 JavaScript 來處理這個問題:

var colorPalette = ['000000', 'FF9966', '6699FF', '99FF66','CC0000', '00CC00', '0000CC', '333333', '0066FF', 'FFFFFF'];
                     
var forePalette = $('.fore-palette');
 
for (var i = 0; i < colorPalette.length; i++) {
  forePalette.append('<a href="#" data-command="forecolor" data-value="' + '#' + colorPalette[i] + '" style="background-color:' + '#' + colorPalette[i] + ';" class="palette-item"></a>');
}

注意這里我也給每個顏色值設置了一個 data-value 屬性,后面可以作為 execCommand 方法的 ValueArgument 參數。

第二個問題是,我們總不能一直顯示那么多顏色塊吧,這樣會占用很大的空間,給用戶帶來不好的體驗。通過一些簡單的 CSS,就可以實現一個不錯的效果:只有當用戶把鼠標移上按鈕時,才會顯示調色板。

按鈕的節點結構需要調整為:

<div class="fore-wrapper"><i class='fa fa-font'></i>
  <div class="fore-palette">
  </div>
</div>

要讓按鈕在鼠標移上時才顯示,我們需要添加以下 CSS:

.fore-palette,
.back-palette {
  display: none;
}
 
.fore-wrapper:hover .fore-palette,
.back-wrapper:hover .back-palette {
  display: block;
  float: left;
  position: absolute;
}

在 CodePen 的 示例 中,還有許多其它的 CSS 代碼用於美化工具欄,但核心功能所需的就只有上面這些。

 

給編輯器添加功能

現在,是時候來實現我們的編輯器的功能了。所需的代碼驚人的少:

$('.toolbar a').click(function(e) {
     
  var command = $(this).data('command');
   
  if (command == 'h1' || command == 'h2' || command == 'p') {
    document.execCommand('formatBlock', false, command);
  }
   
  if (command == 'forecolor' || command == 'backcolor') {
    document.execCommand($(this).data('command'), false, $(this).data('value'));
  }
   
  if (command == 'createlink' || command == 'insertimage') {
    url = prompt('Enter the link here: ','http:\/\/');
    document.execCommand($(this).data('command'), false, url);
  }
   
  else document.execCommand($(this).data('command'), false, null);
   
});

我們偵聽了工具欄上所有按鈕的點擊事件,當按鈕被點擊時,將其 data-commond 屬性的值保存到變量 commond 中,用於后面執行 execCommand 方法的相應命令,避免重復獲取,也使代碼更加簡潔。

設置字體顏色(foreColor)和背景顏色(backColor)時,使用了 data-value 屬性的值作為第三個參數。

對於創建鏈接(createLink)和插入圖片(insertImage)命令所需的 url 參數,使用了一個提示彈框(prompt)來獲取用戶輸入的值。當然你也可以添加一些額外的邏輯來檢測 url 的有效性。

如果 command 變量不滿足上面所有的 if 條件,則執行默認的 execCommand 命令。

 

這個就是我們實現出來的 WYSIWYG 編輯器

你也可以使用我 上個教程 介紹的 localStorage 來實現自動保存功能。

 

跨瀏覽器差異

對於 execCommand,不同的瀏覽器會有不同的實現。例如 formatBlock,IE 只支持標題標簽(h1-h6)、addresspre,甚至在指定 commandName 時還需要包含標簽符,如 <h3>

也不是所有的瀏覽器都支持所有的命令,IE 就不支持 insertHTMLhiliteColorinsertBrOnReturn 只有 Firefox 支持。

更多瀏覽器差異,可以參考 這個 GitHub 頁面

 

最后的感想

創建自己的 WYSIWYG 編輯器是一個非常好的學習過程,在本篇教程中,討論了許多 execCommand 命令,使用了一些 CSS 來處理基礎外觀。作為練習,建議大家通過文本選擇器(text selection)實現一個工具欄按鈕,用於設置字體(font),實現方法和字體顏色(foreColor)按鈕類似。

希望大家喜歡這篇教程,並能從中學到一些新的東西。


免責聲明!

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



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