自己動手實現簡易的div可編輯富文字框及按下tab鍵後增加4個空格功能
需求分析:
最近需要製作一個簡單的使用者評論輸入框,在網上找了一些富文字輸入框,但是它們的功能太多,不適合自己的需求,於是決定自己動手實現一個簡易的富文字輸入框。
第一步:
想要實現富文字輸入框並不是難事,在<div>標籤內加入 contenteditable="true" ,這個div元素就可以編輯了,而且它的innerhtml 就是保留格式的html文字。
第二步:
只需要寫一些css程式碼給div元素設計一些簡單的樣式,就可以讓輸入框變得美觀。
實現按下tab鍵後增加四個空格的功能:
在不寫額外程式碼的情況下,按下tab鍵,游標會離開編輯框,這是預設行為。所以需要監聽按下tab的事件,在處理函式中取消瀏覽器的預設行為。
然後要想在游標處按下tab鍵,插入四個空格,就需要了解瀏覽器的游標物件。
在瀏覽器中,如果我們選中一片區域,就是看到的變藍色的區域,這塊區域是一個selection物件,selection在ff和chrome瀏覽器可以直接用 window.getSelection()獲取,在HTML裡面,selection只有一個的,它是有開始和結束的。現在在頁面上隨意選中一些元素,按F12,在console 中輸入window.getSelection(); 就可以看到這個selection物件的全部成員。
其中anchorNode (baseNode)是選擇區域的開始節點,focusNode (extendNode)是選擇區域的結束節點,注意: 這裡的開始表示按下滑鼠的位置,結束指的是放開滑鼠的位置,anchoNode不一定在focusNode的前面,因為有的區域可能是從後往前選的。
anchorOffset 返回一個數字,其表示的是選區起點在 anchorNode 中的位置偏移量。
focusOffset 返回一個數字,其表示的是選區終點在 focusNode 中的位置偏移量。
isCollapsed 返回一個布林值,用於判斷選區的起始點和終點是否在同一個位置。
rangeCount 返回該選區所包含的連續範圍的數量。
從type可以看到selection的種類其實是range物件
具體的資訊可以在 具體文件 中檢視,基本包含所有資訊。
只得到selection物件是不能對選區進行操作的,很多屬性都是隻讀許可權,要對選區進行修改,就需要獲得選取的range物件,range提供了很多的函式,可與對選取進行修改。
對選取的修改有兩種方式:
1、獲取 range物件 是通過 window.getselection().getRangeAt(0) 獲取的,然後呼叫range的成員函式進行修改
2、直接建立一個新的range物件,如下:range = document.createRange();
然後對新建的range物件進行需要的修改,最後將selection的原有range刪除,將新建的range物件加進去,替換掉原來的。
selection.removeAllRanges();
selection.addRange(range);
再來補充range的知識:
commonAncestorContainer 是選中元素共同的祖先元素
endContainer是結束元素 endOffset是在endContainer中的結束位置
startContainer是開始元素的位置 startOffset是 startContainer 中的開始點位置。
collapsed 是表示起始和終止是否在同一個位置,如果不再,表現的是選中的區域,如果在同一個位置,顯示的就是輸入游標。
具體的成員函式和變數的使用方法詳見 傳送門
..........................................................................................................................................................................................................................................
我實現按下tab 增加4個空格的思路是 : 自己構造一個文字標籤,裡面的內容是4個   ,將這個元素插入到游標之後,就可以實現四個空格的縮排。(前提是這個文字框是富文字編輯框)
以下我附上自己實現的富文字編輯框的全部程式碼,使用的vue,可以直接放在vue的一個元件裡, 我實現的文字框還帶有一些收縮展開的css動畫。
<!--html部分-->
<template>
<div class="edit-line">
<div contenteditable="true" class="edit-content" placeholder="吐槽一下.." @focus="distransparent"
@blur="transparent" ref="edit" @keydown.tab.stopdefault="tab"></div>
<button @click="send" ref="send" style="opacity: 0.5">提交</button>
</div>
</template>
以下是js部分,有詳細的註釋
實現按下tab進行縮排的是tab()函式 ,event是監聽的原生的tab按鍵物件
<script>
export default {
name: 'editor',
methods: {
transparent () {
this.$refs.send.$el.style = 'opacity:0.5;';
},
distransparent () {
this.$refs.send.$el.style = 'opacity:1;';
},
tab (event) {
// 阻止預設切換元素的行為
if (event && event.preventDefault) {
event.preventDefault()
} else {
window.event.returnValue = false
}
// 獲取游標的range物件 event.view 是一個window物件
let range = event.view.getSelection().getRangeAt(0);
// 游標的偏移位置
let offset = range.startOffset;
// 新建一個span元素
let span = document.createElement('span');
// 四個 表示四個空格
span.innerHTML = ' ';
// 建立一個新的range物件
let newrange = document.createRange();
// 設定新的range的位置,也是插入元素的位置
newrange.setStart(range.startContainer, offset);
newrange.setEnd(range.startContainer, offset);
newrange.collapse(true);
newrange.insertNode(span);
// 去掉舊的range物件,用新的range物件替換
event.view.getSelection().removeAllRanges();
event.view.getSelection().addRange(range);
// 將游標的位置向後移動一個偏移量,放到加入的四個空格後面
range.setStart(span, 1);
range.setEnd(span, 1);
}
}
}
</script>
最後是css程式碼<style scoped>
.edit-line {
width: 100%;
height: 100%;
line-height: 25px;
display: flex;
align-items: center;
}
.edit-content {
transition: width 400ms ease-in;
width: 80%;
/*max-height: 45px;*/
height: 100%;
outline: 0;
padding: 0 4%;
border: 1px solid #dddddd;
border-radius: 12px;
margin: 0 2%;
overflow: auto;
background-color: rgba(255, 255, 255, 0.4);
font-size: larger;
/*!*保證只能寫入文字資訊,不能是富文字*!*/
/*-webkit-user-modify: read-write-plaintext-only*/
}
.edit-content:empty {
width: 35%;
color: lightgray;
}
.edit-content:empty::before {
content: attr(placeholder);
}
.edit-content:focus {
background-color: white;
width: 80%;
}
</style>
通過了解selection物件和range物件,以後想要給自己的編輯器新增定製的功能,都是比較類似的用法了。