前言
富文本編輯器在很多互聯網領域被廣泛應用,特別是各種Web端的程序,比如我們常用的電子郵件、社交平臺、博客編輯平臺等等。目前,有很多針對富文本編輯器的一些基本功能和拓展封裝成一個開源的富文本編輯器,比如最開始百度的Ueditor
,現在比較流行的Quill
、BraftEditor
。對于一些簡單的編輯功能,很多都是直接使用這些開源富文本編輯器的基礎API,如果有其他的額外需求,還會在此基礎上做一些拓展,而且這些開源的富文本編輯器都有開放的拓展API供我們使用。
那么這些富文本編輯器到底是如何實現的呢?
富文本編輯器介紹
富文本編輯器的基本結構通常是一個容器元素(例如 <div>
), 這個容器元素的 contenteditable
屬性被設置為 true
,以允許用戶對其內部的內容進行編輯。這個屬性是實現富文本編輯器的基礎。
富文本編輯器利用 JavaScript
的 DOM
操作來實現各種功能。編輯器通過獲取編輯區域的 DOM
引用,并利用 DOM API
來操作文本內容和樣式。
編輯器通常會附帶一些工具欄,用于設置文本樣式、插入圖片等功能。這些功能會要處理各種用戶交互,比如鍵盤輸入、鼠標點擊、文本選擇等,需要通過為編輯器元素添加事件監聽器,并在相應事件發生時執行特定的操作。
富文本編輯器可以將編輯區域內的 HTML 結構轉換為其他格式,如純文本、Markdown 等。這是為了適應不同的場景和需求,比如將編輯的文本內容保存到數據庫、發送電子郵件等。
富文本編輯器最后輸入的內容需要存儲到后臺,比如HTML字符串存儲,后續獲取進行編輯的時候也是拿到之前保存的HTML進行編輯器內部渲染。
光標位置和選擇范圍管理:富文本編輯器需要跟蹤光標的位置以及用戶的選擇范圍。這使得編輯器能夠準確地應用樣式和執行操作,比如插入鏈接、刪除文本等。
總的來說,富文本編輯器其實就是HTML、CSS 和 JavaScript三者結合,只要好好使用這三樣API,就能實現一個富文本編輯器。
要實現富文本編輯器需要了解哪些API
contenteditable
屬性:該屬性用于使元素可編輯。通過將其設置為"true",可以使元素具備編輯功能。
innerHTML
屬性:這個屬性用于獲取或設置元素的 HTML 內容。通過讀取或修改該屬性,可以獲取或更改編輯區域的內容。
execCommand()
方法:這個方法用于執行命令,比如設置字體樣式、插入鏈接、插入圖像等。使用該方法可以通過命令名稱來執行編輯操作。例如:通過執行document.execCommand('bold')
,可以將選定的文本設置為粗體.
Selection
對象:這個對象提供了與文本選擇相關的信息和操作。可以使用 Selection
對象獲取光標位置、選擇范圍以及進行文本插入、刪除等操作。
Range
對象:Range
對象表示文檔中的一個范圍區域,可以用于精確地控制選定的文本范圍。它提供了一系列的方法和屬性,可以進行文本選取、插入、刪除等操作。
Selection對象
Selection 對象表示用戶當前選擇的文本范圍,它提供了獲取和操作選中文本的方法和屬性。
屬性和方法
anchorNode
: 返回當前選擇范圍的起始節點(節點可以是元素節點或文本節點)。
anchorOffset
: 返回當前選擇范圍的起始偏移量,即在 anchorNode 中的偏移位置。
focusNode
: 返回當前選擇范圍的結束節點。
focusOffset
: 返回當前選擇范圍的結束偏移量。
isCollapsed
: 判斷當前選擇范圍是否是折疊的(即光標狀態)。
removeAllRanges()
: 清除所有選擇范圍。
addRange(range)
: 添加一個 Range 對象到當前選擇中。
toString()
: 返回選中文本的字符串表示。
Range對象
Range 對象表示文檔中的一個范圍區域,可以用于精確地控制選定的文本范圍
屬性和方法
startContainer
: 返回當前范圍的起始節點(元素節點或文本節點)。
startOffset
: 返回當前范圍在 startContainer 中的起始偏移量。
endContainer
: 返回當前范圍的結束節點。
endOffset
: 返回當前范圍在 endContainer 中的結束偏移量。
commonAncestorContainer
: 返回包含當前范圍內所有節點的最深的共同祖先節點。
selectNode(node)
: 選中指定的節點。
selectNodeContents(node)
: 選中指定節點的內容。
setStart(startNode, startOffset)
: 設置范圍的起始位置。
setEnd(endNode, endOffset)
: 設置范圍的結束位置。
insertNode(node)
: 在當前范圍內插入一個節點。
deleteContents()
: 刪除當前范圍內的內容。
Selection和Range在針對文本的相關操作是很有用的兩個API,這里我主要是總結幾個重要的一些屬性和方法,具體的一些使用場景后續有機會再出一篇相關文章。
這種應用場景目前就有一個很好的例子:劃線分享。簡單說明一下,劃線分享就是確定開始光標位置和結束位置,然后確定選定文本的范圍,最后給選定的文本段設置一個特殊的樣式區分顯示,彈出對應的功能按鈕分享。這里不就主要用Selection和Range嘛。
實現一個簡單的富文本編輯器
創建編輯區域
首先需要一個編輯區域,創建一個div
元素,元素設置contenteditable=true
<div id="editor" contenteditable="true" style="border: 1px solid #ccc; min-height: 200px;"></div>
創建編輯功能Bar
其次,創建一個編輯器工具欄,我們就寫一個最簡單的,設置字體粗細。
<select id="fontStyle">
<option value="normal">Normal</option>
<option value="bold">Bold</option>
<option value="italic">Italic</option>
</select>
<button onclick="setFontStyle()">Set Style</button>
function setFontStyle() {
const fontStyle = document.getElementById('fontStyle').value;
document.execCommand('fontName', false, fontStyle);
}
在 JavaScript 中,我們可以通過獲取選中元素的值和編輯區域的引用,使用 document.execCommand()
方法來設置文本樣式。
內容輸出
通過一個按鈕進行保存,保存的內容主要是通過innerHTML
拿到。
<button onclick="saveContent()">Save Content</button>
function saveContent() {
const editor = document.getElementById('editor');
const content = editor.innerHTML;
console.log(content); // 這里的內容可以通過后臺接口保存到數據庫中
}
以上其實就已經實現了一個特別簡單基礎的富文本編輯器,還有一部分比如一些媒體功能包括插入圖片、插入視頻等,可以按照上面一樣的邏輯添加不同的功能。整體的實現思路大致就是這些。
但是實現過程中有需要注意的地方⚠️:
contenteditable=true
可編輯元素,默認回車會自動生成p
標簽,但是不同瀏覽器的表現不一樣,火狐和谷歌瀏覽器默認新建p
標簽,safari默認新建div
標簽,且第一個初始生成的p
標簽會被砍掉只保留了文字部分。這里需要手動去創建一個特定的標簽。
刪除內容,需要注意刪除到最后要保留之前初始化的空標簽,不然會默認把初始化的空標簽刪掉,這樣生成的html就不一致了。
最后
這次主要是介紹一下實現簡單富文本編輯器的一個基礎流程,其實他的核心就是contenteditable=true
,如果需要實現一個更好的富文本編輯器,就需要結合各個API進行事件處理和樣式處理。目前也有好的開源富文本編輯器,我們可以參考他們的源碼實現一個自己的富文本編輯器,這樣不僅能夠讓自己對于一些API理解更深刻,而且關于一個完整的開源功能也有一個很好的認知。
作者:Betty97
鏈接:https://juejin.cn/post/7240751116702122021
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
該文章在 2023/12/28 11:00:34 編輯過