關於selection和range的一些認識
關於selection和range的一些認識
因為最近做了大量的編輯器相關的需求,必不可少的認識了這兩個概念。剛開始接觸這兩個概念的同學肯定還是會蒙圈的,冉義分不清楚這兩個是幹啥的。今天就來大致的分列一下他們的api和功能。
selection對象
首先,一個可編輯的區域,用戶在操作時,是通過selection對象來進行操作的。當你選中一塊區域,或者游標聚焦一個點時,都會創建一個selection對象。這時候,你可以通過document.getSelection()來取得這時候創建的對象。我們可以來看一些selection中的內容。
如上文本中的選區獲得的selection中,包含了archorNode,baseNode,extentNode,focusNode這幾個節點和一些屬性,我們一個個來講。
archnorNode(只讀)
返回該選區起點所在的節點(Node
)。比如,一個選中區由滑鼠事件產生,那archnorNode就是滑鼠按下時所在的節點。
archnorOffset(只讀)
返回一個數字,其表示的是選區起點在anchorNode
中的位置偏移量。
- 如果 anchorNode 是文位元組點,那麼返回的就是從該文位元組點的第一個字開始,直到被選中的第一個字之間的字數(如果第一個字就被選中,那麼偏移量為零)。
- 如果 anchorNode 是一個元素,那麼返回的就是在選區第一個節點之前的同級節點總數。(這些節點都是 anchorNode 的子節點)
如圖上,archnorNode是當前的textnode節點,archnorOffset為向右偏移了12
focueNode(只讀)
返回該選區終點所在的節點。
focueOffset(只讀)
返回一個數字,其表示的是選區終點在focusNode
中的位置偏移量。
- 如果 focusNode 是文位元組點,那麼選區末尾未被選中的第一個字,在該文位元組點中是第幾個字(從0開始計),就返回它。
- 如果 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。
參數結構示意圖:
推薦閱讀: