在普通的 textarea 中,只能顯示普通的文本。若是簡單的輸入文本,textarea 便足以勝任。可是實際狀況每每要複雜得多。html
常見的版本通常都是使用 textarea,而後表情使用某種約定的文本格式代替,好比「你好啊[微笑]」。在呈現的時候,經過固定的文本解析方法將內容中的表情文本替換成圖片。新浪微博中發微博的輸入框就是如此。可是,在這有一點須要注意,若是隻是簡單的在文本的最後插入表情之類的預約好的文本格式,只需獲取到到 textarea 的 value 而後作加法便可。前端
let editor = document.querySelect('#editor'); editor.value += '[微笑]';
但實際狀況卻沒有這麼簡單,由於用戶能夠本身選擇光標的位置。當用戶在某一段文本中間插入光標以後,可不是簡單的加法了。在這種狀況下,須要獲取到光標所在位置,在這個位置上插入用來代替表情的文本,而後將光標設置到表情文本的後面。在這須要兩個額外的方法:getCaretPosition
和 setCaretPosition
。segmentfault
瀏覽器並無提供直接獲取光標位置的方法,須要咱們變通的處理。瀏覽器基本上都支持文本框的select()
方法,這個方法用於選中文本框中全部的文本,可是隻能乖乖的拿到返回的全部文本。HTML5 添加了兩個屬性:selectionStart 和 selectionEnd 幫助咱們更加順利地獲取選擇的文本。這兩個屬性中保存的是基於0的數值,表示所選擇的文本的範圍,分別表示文本選區(選中的文本)開頭和結尾相對整個文本內容的偏移量(在整個文本內容中的位置)。例如:瀏覽器
let editor = document.querySelector('#editor'); // 從第一個字符開始,選中三個字符 editor.selectionStart = 0; editor.selectionEnd = 1; // 從第三個字符開始選中三個字符 editor.selectionStart = 2; editor.selectionEnd = 5;
說到這你可能要問了,這個光標有啥關係啊?別急,聽我慢慢說。既然上述兩個設置不一樣數字能夠選擇文本,那若是兩個值設置成相同的數字,會怎麼樣呢?code
// 從第三個字符開始選中零個字符 editor.selectionStart = 2; editor.selectionEnd = 2;
起點和終點重合了!那麼換個角度來描述就是:當咱們在獲取光標位置的時候,其實就是選中的文本範圍起點和重點重合,至關於文本範圍的起點偏移量其實就是光標所在的位置偏移量,因此此時selectionStart
的返回值就是咱們須要的結果。htm
更關鍵的是,當 End 和 Start 設置成相同值時,選區也是空的,起點和重點充電,就好像是設置了光標的位置。其實有一個簡便的方法 setSelectionRange(start, end),原理相同。對象
固然有興趣你也能夠試試 End小於 Start的狀況。上述這些在現代瀏覽器和 IE9+ 上都支持。圖片
前端向來麻煩的仍是瀏覽器的兼容問題。在低版本的 IE 中只能使用 document.selection
對象來模擬光標定位了。document.selection
只存在於 IE8 及更早的版本(可使用 window.getSelection 代替),保存着用戶在整個文檔範圍內選擇的文本信息,可是沒法肯定用戶選擇的是頁面中哪一個部位的文本。要想取得選擇的文本,首先須要建立一個範圍(Range,IE9+ 支持 DOM Range API,可是 IE8及以前的版本不支持,可是有相似的概念,text range。這是 IE 專有的特性)。可以使用 document.selection.createTextRange
來建立咱們所須要的 text range。而後利用moveStart().aspx)將文本的範圍的起點從當前位置(當前位置起點和重點是重合的)移動到文本的開頭,而後計算選中文本的長度,這個長度值能夠用來代替當前光標的位置。文檔
let range = document.selection.createRange(); range.moveStart("character", editor.value.length); cursurPosition = range.text.length;
設置光標位置思路相似,可是代碼稍有不一樣:get
let range = editor.createTextRange(); range.collapse(true); range.moveEnd('character', pos); range.moveStart('character', pos); range.select();
總的來講,在 textarea 中獲取和設置光標位置仍是蠻簡單的。講到這裏了,我想插入表情應該是很輕鬆的一件事情了
獲取光標位置(文本範圍先後重疊) -> 修改文本範圍(或者手動拼接) -> 從新設置光標位置
至此,表情插入功能的基本實現。
上述例子中,在輸入框中表情只能以文本的形式呈現。若是想在輸入框中呈現輸入的表情,該怎麼辦呢?使用 contenteditable 屬性爲 true 的容器代替 textarea 是必須的,由於 textarea 中只能顯示文本。可是這就足夠了嗎?不,顯然不夠。沒有了 textarea 則覺得這沒有了 setSelectionRange, selectionStart 和 selectionEnd。可是好在原理也是相似,依舊使用 Range API 或者 Text Range(IE8及其更低版本)。具體的能夠參考這篇:html元素contenteditable屬性如何定位光標和設置光標和這篇在可編輯的div中插入圖片。 具體實現代碼我就不貼了,你們能夠本身思考捋一捋。觸類旁通,若是你真真正正地知道如何正確插入圖片,那麼插入複雜的 DOM 結構對你來講也是垂手可得。