前端培訓-初級階段-場景實戰(2019-05-09)-聊天框-發送框

前端最基礎的就是 HTML+CSS+Javascript。掌握了這三門技術就算入門,但也僅僅是入門,如今前端開發的定義已經遠遠不止這些。前端小課堂(HTML/CSS/JS),本着提高技術水平,打牢基礎知識的中心思想,咱們開課啦(每週四)。css

初級階段已經完結,以後會針對以前提到過的內容,對實際場景進行分享。正好前段時間我不是一直在加班作聊天的功能嘛。今天咱們就來講一說其中遇到的東西。html

咱們要講什麼?

聊天功能中的發送框的實現及一些常規操做的實現。前端

  1. contentEditable
  2. Node 與 Element
  3. 插入功能(表情、截圖等等)
  4. 粘貼功能
  5. 拖入功能

測試地址-測試下面的特性node

關鍵詞 文字 換行 圖片
input × ×
textarea ×
contentEditable

contentEditable

你會說這東西我知道,給元素加上就能夠編輯內容。老鐵,這麼簡單固然不行了。web

  1. 當你按下Enter/Return鍵在可編輯區域中建立一個新的文本行時,不一樣主流瀏覽器對此有不一樣處理(Firefox 插入
    、IE/Opera將使用<p>、 Chrome/Safari 將使用 <div>)
  2. css 也能夠支持一樣的功能-webkit-user-modify,值有api

    1. inherit(繼承);
    2. initial(默認);
    3. read-only(只讀);
    4. read-write(讀寫);
    5. read-write-plaintext-only(讀寫、非富文本);
    6. unset(未設置);當一個屬性定義了unset值,若是該屬性是默認繼承屬性,該值等同於inherit,若是該屬性是非繼承屬性,該值等同於initial
  3. 同上 contentEditable 屬性支持的也不是邏輯值。plaintext-only 就是其中最亮的仔。
    最先仍是在張鑫旭大佬-小tip: 如何讓contenteditable元素只能輸入純文本哪裏看的到的

固然咱們用的仍是富文本的樣式。由於咱們裏面須要表情瀏覽器

Node 與 Element

Node

Node 是一個接口,許多 DOM API 對象的類型會從這個接口繼承。它容許咱們使用類似的方式對待這些不一樣類型的對象;好比, 繼承同一組方法,或者用一樣的方式測試。
如下接口都從 Node 繼承其方法和屬性:
Document, Element, Attr, CharacterData (which Text, Comment, and CDATASection inherit), ProcessingInstruction, DocumentFragment, DocumentType, Notation, Entity, EntityReference
----------------- https://developer.mozilla.org...
  1. Node.nodeName
    返回一個包含該節點名字的DOMString。節點的名字的結構和節點類型不一樣。
    HTMLElement 的名字跟它所關聯的標籤對應,好比 HTMLAudioElement 對應的是 'audio'
    Text 節點對應 '#text'
    Document 節點對應 '#document'
  2. Node.nodeType安全

    Name Value status
    ELEMENT_NODE 1
    ATTRIBUTE_NODE 2 warn
    TEXT_NODE 3
    CDATA_SECTION_NODE 4
    ENTITY_REFERENCE_NODE 5 warn
    ENTITY_NODE 6 warn
    PROCESSING_INSTRUCTION_NODE 7
    COMMENT_NODE 8
    DOCUMENT_NODE 9
    DOCUMENT_TYPE_NODE 10
    DOCUMENT_FRAGMENT_NODE 11
    NOTATION_NODE 12 warn

上面兩個屬於比較重要的app

Element

Element是很是通用的基類,全部 Document對象下的對象都繼承它. 這個接口描述了全部相同種類的元素所廣泛具備的方法和屬性。 這些繼承自Element而且增長了一些額外功能的接口描述了具體的行爲. 例如, HTMLElement 接口是全部HTML元素的基礎接口, 而 SVGElement 接口是全部SVG元素的基本接口.大多數功能在類的層次中進一步制定.
在web之外的語言,像 XUL 能夠經過 XULElement 接口, 一樣也實現了Element接口.

Node 與 Element 差異

Node 中是會包含文本節點的。好比Text。
而 Element 包含的都是標籤節點。wordpress

插入功能

若是換成 DOM 操做,好像功能還蠻簡單的 appendChildinsertBeforereplaceChild好像就基本能夠搞定了。可是換到富文本中呢?咱們須要解決幾個問題

  1. 獲取當前焦點位置
  2. 在文本內容中插入內容
  3. 在節點內容中插入內容
  4. 其實還有一點,插入的時候會單擊其餘位置,致使焦點丟失,因此咱們須要記住,而後設置到指定位置。

獲取當前的焦點位置

window.getSelection();這個能夠用來獲取焦點位置。
anchorNode 指向用戶開始選擇(按下鼠標鍵)的地方,而 focusNode 指向用戶結束選擇(鬆開鼠標鍵)的地方。
注意不能與選區的起始位置和終止位置混淆,由於開始選擇的位置可能在結束選擇位置的前面,也可能在結束選擇位置的後面,這取於選擇文本時鼠標移動的方向(也就是按下鼠標鍵和鬆開鼠標鍵的位置)
isCollapsed 布爾值,用於判斷選區的起始點和終點是否在同一個位置。

//能夠用這段代碼來觀察
setInterval(()=>{
    var selection=window.getSelection();
    console.log(selection)
},1000)

clipboard.png

文本內容中插入內容

從上面的內容中,咱們能夠看到,在文本中是一個 Node 節點,那我應該如何插入節點呢?這其實就是調用 insertData 這個api就行了。可是,怎麼能如此簡單呢?咱們插入的是 DOM 而不是簡單的文本,因此這個操做不能用。
clipboard.png
這裏咱們要用的實際上是splitText,用於在焦點處分割開內容。而後再after增長內容。
clipboard.png
clipboard.png

在節點中插入內容

這個就比較簡單了。節點的話,直接加入進去就行了。由於節點不存在說中間插入。可是呢,當你在節點以後的時候,你須要獲取其中全部的 nodes 而後根據 offset找到點。childNodeschildren 該使用那個呢?這個就涉及到上面說到的 NodeElement 的區別,留個小做業,本身試一下吧。友情提示,報錯的時候記得看是否是 anchorNodeText 節點

clipboard.png

記錄焦點位置&整合應用

既然點擊會失去焦點,那麼咱們在blur的時候記錄。而後給顯示回去就OK了。
測試地址,其實還有一個效果沒處理,那就是選區處理。能夠當作一個課後做業。

粘貼功能

這個功能很坑,由於仍是富文本。因此粘貼進來的是有樣式的。可是咱們不須要樣式,因此咱們要過濾掉全部的標籤。可是又由於咱們能夠複製粘貼圖片。因此咱們須要過濾出來咱們的圖片。
方案有兩種

  1. 獲取文本,圖片會變成alt屬性標識的值(我用的是這個)
  2. 獲取HTML,須要本身去過濾處理。

粘貼進來的內容,咱們須要處理 paste 事件。 e.clipboardData 是獲取剪貼板對象。提供了 getData 來獲取剪貼板內容。好比 getData('text'); 獲取文字內容。getData('text/html'); 獲取html格式內容。

tips:

  1. 能夠複製單圖片。會在粘貼板中 files 裏面。
  2. 不能夠執行 setData 方法,看上去是瀏覽器廠商出於安全方向考慮。因此不能直接人爲替換剪貼板內容達到目的。那麼咱們要注意 e.preventDefault();,用來阻止默認的事件。

拖拽功能

這個功能沒實現,感受上很難,達不到原生的那種感受,也有多是我api沒找到,但願會的人告我一下
說一下我能給出的方案,由於不能 setData 因此方案仍是考慮阻止默認的

  1. 分開處理,內部拖拽使用系統操做。外部拖拽禁止。
  2. 都使用本身的處理可是拿不到焦點,針對這個問題,能夠作到增長提示,而後追加。
  3. 拖拽的話,能夠有文件級別的。判斷若是是文本文件之類的,能夠讀取文件內容。

後記

主講人文章-瀏覽器科普
感謝評論區的回覆, document​.exec​Command --MDN 的支持用起來的確會少控制一些邏輯。

相關文章
相關標籤/搜索