關於selection和range的一些認識

因為最近做了大量的編輯器相關的需求,必不可少的認識了這兩個概念。剛開始接觸這兩個概念的同學肯定還是會蒙圈的,冉義分不清楚這兩個是幹啥的。今天就來大致的分列一下他們的api和功能。

selection對象

首先,一個可編輯的區域,用戶在操作時,是通過selection對象來進行操作的。當你選中一塊區域,或者游標聚焦一個點時,都會創建一個selection對象。這時候,你可以通過document.getSelection()來取得這時候創建的對象。我們可以來看一些selection中的內容。

如上文本中的選區獲得的selection中,包含了archorNode,baseNode,extentNode,focusNode這幾個節點和一些屬性,我們一個個來講。

archnorNode(只讀)

返回該選區起點所在的節點(Node)。比如,一個選中區由滑鼠事件產生,那archnorNode就是滑鼠按下時所在的節點。

archnorOffset(只讀)

返回一個數字,其表示的是選區起點在anchorNode 中的位置偏移量。

  1. 如果 anchorNode 是文位元組點,那麼返回的就是從該文位元組點的第一個字開始,直到被選中的第一個字之間的字數(如果第一個字就被選中,那麼偏移量為零)。
  2. 如果 anchorNode 是一個元素,那麼返回的就是在選區第一個節點之前的同級節點總數。(這些節點都是 anchorNode 的子節點)

如圖上,archnorNode是當前的textnode節點,archnorOffset為向右偏移了12

focueNode(只讀)

返回該選區終點所在的節點。

focueOffset(只讀)

返回一個數字,其表示的是選區終點在focusNode 中的位置偏移量。

  1. 如果 focusNode 是文位元組點,那麼選區末尾未被選中的第一個字,在該文位元組點中是第幾個字(從0開始計),就返回它。
  2. 如果 focusNode 是一個元素,那麼返回的就是在選區末尾之後第一個節點之前的同級節點總數。

isCollapsed

返回一個布爾值,用於判斷選區的起始點和終點是否在同一個位置。

rangeCount

返回該選區所包含的連續範圍的數量。

type(非正式,測試屬性)

  • None: 當前沒有選區
  • Caret: 選區被摺疊,isCollapsed為true時(caret被放在一些文本中,但是沒有範圍range被選中,如一個游標)
  • Range:一個range存在

除了這些只讀的屬性,selection還暴露了一些api用以操作選中區域。

sel.getRangeAt(index)

range = sel.getRangeAt(index)

返回一個包含當前選區內容的區域對象(range)。這裡的index的範圍是連續選區的個數,及index不能比rangeCount大,否則它會報錯。

collapse,collapseToStart,collapseToEnd

sel.collapse()

方法可以收起當前選區到一個點。文檔不會發生改變。如果選區的內容是可編輯的並且焦點落在上面,則游標會在該處閃爍。這主要的作用是形成一個游標,可讓選中區聚焦。collapseToStart和collapseToEnd其實做了一樣的事,只不過一個摺疊到選區的開始,一個摺疊到選區的結束。

addRange

sel.addRange(Range)

添加一個新的選區range到當前selection中。

removeRange

sel.removeRange(range)

移除一個特定的range。

Range對象

range對象,代表一個連續的選中區域。range可以直接從selection.getRangeAt(index)的方式來拿,可以直接document.createRange() 的方式來創建。

先來看幾個只讀的range的屬性:

Range.collapsed返回一個用於判斷 Range 起始位置和終止位置是否相同的布爾值。

Range.commonAncestorContainer返回包含 startContainer 和 endContainer 的最深的節點。

Range.endContainer返回包含 Range 終點的節點。

Range.endOffset返回 endContainer 中表示Range終點位置的數字。

Range.startContainer返回包含 Range 開始的節點。

Range.startOffset返回 startContainer 中表示 Range 起始位置的數字。

這些主要是一些節點的信息。

然後看幾個常用的api:

Range.setStart() 和Range.setEnd()

用於設置Range的開始位置和結束位置。使用:

range.setStart(startNode,startOffset)range.setEnd(startNode,startOffset)

這裡的node和offset分別為需要設置的起始點(結束點)所在的節點和偏移量。

range.setStartBefore(),Range.setStartAfter(),Range.setEndBefore(),range.setEndAfter()幾個方法都是以其它節點為基準,來設置 Range 的起始點或者終點。

Range.selectNode()

這個方法主要用於將range包含在某個特定node節點下

editor=document.getElementById("editor")range=document.createRnage();range.selectNode("editor")

這樣就創建了一個range並將range包含了整個id為editor所在的元素。

Range.selectNodeContents()

這個方法主要用於將range包含在某個特定node節點內,但是不包含node,只包含node 節點內的內容。

編輯方法

通過以下方法,可以從 Range 中獲得節點,改變 Range 的內容。

range.cloneContents()

返回 Range 當中節點的文檔片段(DocumentFragment)。

Range.deleteContents()

從文檔(Document)中移除 Range 中的內容。這個方法會把range中的內容清空。可用於一些特定的刪除操作。某些特定的情況下,如前端與客戶端的交互中,前端的編輯區域失去焦點後,在iOS10下,不點擊編輯區的話無法再次聚焦,這時,可以先記下之前的range,等再次需要聚焦前端時用deleteContents來代替execCommand(delete)的方案刪除特定字元。

//記下之前的range所在nodevar beforeNode=sel.getRangeAt(0);var focusNode=beforeNode.focusNode;/*******apphost喚起native事件,前端失去焦點。*******//*******apphost事件結束。*******/var range=focusNode//根據node和Offset刪除需要刪除的內容range.setStart(node,offset);range.setEnd(node,offset);range.deleteContents();

Range.extractContents()

把 Range 的內容從文檔樹移動到文檔片段中。

Range.insertNode()

在 Range 的起點處插入節點。可以用於向document中插入一些內容,比如像<div contenteditable="true"></div>的元素在使用普通的execCommand(insertHtml)的方法來粘貼時,會丟掉contenteditable屬性,而使用選區的方法則可以保留。

Range.surroundContents()

將Range 的內容移動到一個新的節點中。

Range.getBoundingClientRect()

方法返回元素的大小及其相對於視口的位置。如下是選區一些參數的獲取(寬高和坐標)。不過在ios下,以游標作為選區時,取到 的這些參數都是0。

參數結構示意圖:

推薦閱讀:

相关文章