輸入框插入表情的實現

在普通的 textarea 中,只能顯示普通的文本。若是簡單的輸入文本,textarea 便足以勝任。可是實際狀況每每要複雜得多。html

簡單版本的插入表情

常見的版本通常都是使用 textarea,而後表情使用某種約定的文本格式代替,好比「你好啊[微笑]」。在呈現的時候,經過固定的文本解析方法將內容中的表情文本替換成圖片。新浪微博中發微博的輸入框就是如此。可是,在這有一點須要注意,若是隻是簡單的在文本的最後插入表情之類的預約好的文本格式,只需獲取到到 textarea 的 value 而後作加法便可。前端

let editor = document.querySelect('#editor');
editor.value += '[微笑]';

沒你想的這麼簡單

但實際狀況卻沒有這麼簡單,由於用戶能夠本身選擇光標的位置。當用戶在某一段文本中間插入光標以後,可不是簡單的加法了。在這種狀況下,須要獲取到光標所在位置,在這個位置上插入用來代替表情的文本,而後將光標設置到表情文本的後面。在這須要兩個額外的方法:getCaretPositionsetCaretPositionsegmentfault

getCaretPosition/setCaretPosition

瀏覽器並無提供直接獲取光標位置的方法,須要咱們變通的處理。瀏覽器基本上都支持文本框的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 結構對你來講也是垂手可得。

相關文章
相關標籤/搜索