Tìm hiểu về DOM Range
Bài đăng này đã không được cập nhật trong 6 năm
DOM Range là gì?
Range
là một interface trong DOM
(Document Object Model), đại diện cho một phần nội dung của văn bản bao gồm các node và text nodes. Mỗi node có một điểm đầu start
và một điểm cuối end
được gọi là các điểm biên (boundary points). Một điểm biên bao gồm một node và một giá trị offset không âm. Nói cách khác, range đại diện cho một phần văn bản của cây node (node tree) nằm giữa 2 điểm biên.
Range thường được sử dụng cho việc chỉnh sửa các nội dụng đang được bôi đen và copy.
Cách tạo một Range cơ bản
<p>
<img src="insanity-wolf" alt="Little-endian BOM; decode as big-endian!">
CSS 2.1 syndata is
<em>awesome</em> !
</p>
Trong node tree ở ví dụ trên, range có thể đại diện cho đoạn "syndata is awes". Giả sử p
được gán cho element p và em
được gán cho element em. Range được tạo như sau:
var range = new Range(),
firstText = p.childNodes[1],
secondText = em.firstChild
range.setStart(firstText, 9) // do not forget the leading space
range.setEnd(secondText, 4)
// range now stringifies to the aforementioned quote
Lưu ý: Những thuộc tính như src
và alt
trong node tree bên trên không thể được đại diện bởi một range. Khái niệm range chỉ hữu dụng đối đối với các node.
Ngoài cách sử dụng hàm khởi tạo Range(), Range có thể được tạo bởi hàm getRangeAt()
của Selection
object, hàm createRange
hoặc caretRangeFromPoint
của Document
object.
Các thuộc tính và một số phương thức của Range
Thuộc tính:
startContainer
: node đầu tiên của rangestartOffset
: giá trị số không âm thể hiện vị trị bắt đầu của range bên trongstartContainer
endContainer
: node cuối cùng của rangeendOffset
: giá trị số không âm thể hiện vị trí kết thúc của range bên trongendContainer
.commonAncestorContainer
: node gần nhất chứa cảstartContainer
vàendContainer
.collapsed
: trả về giá trị kiểuBoolean
, xác định 2 điểm đầu và cuối của range có trùng nhau hay không.
Phương thức:
-
setStart(Node node, Number offset)
: khởi tạo điểm biên bắt đầu của range. -
setEnd(Node node, Number offset)
: khởi tạo điểm biên kết thúc của range. -
setStartBefore(Node node)
: khởi tạo điểm biên bắt đầu của range ngay phía trước node được chỉ định. -
setStartAfter(Node node)
: khởi tạo điểm biên bắt đầu của range ngay phía sau node được chỉ định. -
setEndBefore(Node node)
: khởi tạo điểm biên kết thúc của range ngay phía trước node được chỉ định. -
setEndAfter(Node node)
: khởi tạo điểm biên kết thúc của range ngay phía sau node được chỉ định. -
selectNode(Node node)
: di chuyển 2 điểm biên của range bao quanh node được chỉ định. Khi nàystartContainer
vàendContainer
đều trỏ tớiparentNode
của node hiện tại. Giả sửi
là giá trị index của node bên trong parent của nó, thìstartOffset
có giá trị lài
vàendOffset
có giá trị lài + 1
Ví dụ, cho đoạn HTML dưới đây :
<p>Watford's all-time top scorer is <b id="luther">Luther Blissett</b> with 186 goals.</p>
Một range có thể được tạo và bao quanh element
<b
> như sau:var range = rangy.createRange(); var b = document.getElementById("luther"); range.selectNode(b);
startContainer
vàendContainer
sẽ cùng trỏ đến elementp
.startOffset
là 1 vàendOffset
là 2. -
selectNodeContents(Node node)
: di chuyển range bao quanh nội dung của node được chỉ định.Trong mọi trường hợp,
startContainer
vàendContainer
đều trỏ đến node hiện tại.Trường hợp node được chỉ định (
node
) có child nodes (ví dụ một element) thì điểm biên bắt đầu được đặt ngay trước child node đầu tiên củanode
và điểm biên kết thúc được đặt ngay sau child node cuối cùng củanode
. Đồng nghĩa làstartOffset
có giá trị 0 vàendOffset
có giá trị bằngnode.childNodes.length
.Đối với
node
không có child node (ví dụ một text node), điểm biên bắt đầu nằm ở vị trí bắt đầu của text và điểm biên cuối nằm ở vị trí kết thúc của text.startOffset
có giá trị 0 vàendOffset
có giá trị bằngnode.length
Ví dụ:
<p>Watford's all-time top scorer is <b id="luther">Luther Blissett</b> with 186 goals.</p>
var range = new Range(); var b = document.getElementById("luther"); range.selectNodeContents(b);
startContainer
vàendContainer
đều trỏ tới element<b>
.startOffset
là 0 vàendOffset
là 1. Nếu gọi hàmselectNodeContents()
với text node bên trong element<b>
như sau:range.selectNodeContents(b.firstChild);
startContainer
vàendContainer
đều trỏ tới text node.startOffset
là 0 vàendOffset
là 15. -
collapse(Boolean toStart)
: gộp range về điểm biên bắt đầu (toStart
=true
) hoặc điểm biên kết thúc (toStart = false). -
cloneContents()
: trả về mộtDocumentFragment
chứa nội dung đã copy từ range hiện tại -
extractContents()
: tách nội dung hiện tại của range thành mộtDocumentFragment
và trả về fragment đó. -
deleteContents()
: xóa nội dung hiện tại của range. -
surroundContents(Node node)
: di chuyển nội dung của range vào bên trong của node chỉ định. Node này sẽ được chèn vào document ở vị trí của range. Hàm này sẽ trả về lỗi nếu range chỉ nằm trên một phần của một node (node chỉ chứa một điểm biên của range). -
cloneRange()
: trả về một range mới có các điểm biên giống với range hiện tại. -
toString()
: trả về nội dung text của range. -
compareBoundaryPoints(Number comparisonType, Range range)
: so sánh biên của range hiện tại với biên của range chỉ định. Trả về lần lượt các giá trị -1, 0, 1 nếu biên của range hiện tại đứng trước, trùng và đứng sau biên của range chỉ định. Điểm biên được so sánh dựa trên giá trịcomparisonType
:START_TO_START
: so sánh điểm biên bắt đầu của 2 range.START_TO_END
: so sánh điểm cuối của range hiện tại với điểm đầu của range chỉ định.END_TO_START
: so sánh điểm đầu của range hiện tại với điểm cuối của range chỉ định.END_TO_END
: so sánh điểm cuối của 2 range.
Những lưu ý khi sử dụng Range
- Các đối tượng Range không cập nhật theo khi DOM thay đổi (ngoại trừ khi việc thay đổi này xuất phát từ các hàm của Range).
- Không một thuộc tính nào của range trả về exception khi chúng được gán trực tiếp.
- Những thuộc tính của một detached range sẽ trả về exception khi được truy cập. Do đó nên tuân thủ những quy tắc sau:
- Tạo một range mới bất kể khi nào văn bản bị thay đổi bởi người dùng hoặc những đoạn code khác.
- Không gán trực tiếp giá trị vào các thuộc tính của range (
startContainer
,endContainer
,startOffset
,endOffset
,commonAncestorContainer
vàcollapsed
). Sẽ không có thông báo lỗi trả về nhưng mọi thứ về sau có thể hoạt động không đúng nếu thực hiện việc gán này.
Tham khảo
- Tim Down, Range objects in Rangy.
- W3C, W3C DOM4.
- MDN Web Docs, Range.
All rights reserved