JavaScript 中的 Range 和 Selection 對象

来源:https://www.cnblogs.com/risheng/p/18208075
-Advertisement-
Play Games

最近在做滑鼠框選的需求,滑鼠框選就需要用到 Range 和 Selection 對象。 Range 表示選擇的區間範圍,Selection 表示選擇的文檔內容。 Range 介面表示一個包含節點與文本節點的一部分的文檔片段。 不僅僅可以用於滑鼠框選,頁面上任何元素、文本都可以創建 Range。 Se... ...


JavaScript 中的 Range 和 Selection 對象

前言

最近在做滑鼠框選的需求,滑鼠框選就需要用到 RangeSelection 對象。

Range 表示選擇的區間範圍,Selection 表示選擇的文檔內容。

下麵就詳細說下這兩個對象

一、Range

Range 介面表示一個包含節點與文本節點的一部分的文檔片段。

不僅僅可以用於滑鼠框選,頁面上任何元素、文本都可以創建 Range

Range 是瀏覽器原生的對象。

image

1. 創建 Range 實例,並設置起始位置

<body>
  <ul>
    <li>Vite</li>
    <li>Vue</li>
    <li>React</li>
    <li>VitePress</li>
    <li>NaiveUI</li>
  </ul>
</body>
<script>
  // 創建 Range 對象
  const range = new Range()
  const liDoms = document.querySelectorAll("li");
  // Range 起始位置在 li 2
  range.setStartBefore(liDoms[1]);
  // Range 結束位置在 li 3
  range.setEndAfter(liDoms[2]);
  // 獲取 selection 對象
  const selection = window.getSelection();
  // 添加游標選擇的範圍
  selection.addRange(range);
</script>

image

可以看到,選擇內容為第二行和第三行

1.1 瀏覽器相容情況

image

2. Range 屬性

  1. startContainer:起始節點。

  2. startOffset:起始節點偏移量。

  3. endContainer:結束節點。

  4. endOffset:結束節點偏移量。

  5. collapsed:範圍的開始和結束是否為同一點。

  6. commonAncestorContainer:返回完整包含 startContainerendContainer 的最深一級的節點。

2.1. 用我們上面創建的實例來看下 range 屬性的值

image

2.2. 如果我們只選擇文本內容時

只選擇 li 中的 itePres

image

可以看出 range 屬性對應的值

image

3. Range 方法

3.1. cloneContents()

cloneContents():複製範圍內容,並將複製的內容作為 DocumentFragment 返回。

const range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
const documentFragment = range.cloneContents();
document.body.appendChild(documentFragment);

3.2. cloneRange()

cloneRange():創建一個具有相同起點/終點的新範圍, 非引用,可以隨意改變,不會影響另一方。

const range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
const clone = range.cloneRange();

3.3. collapse()

collapse(toStart):如果 toStart=true 則設置 end=start,否則設置 start=end,從而摺疊範圍。

const range = document.createRange();
const referenceNode = document.getElementsByTagName("div").item(0);
range.selectNode(referenceNode);
range.collapse(true);

3.4. compareBoundaryPoints()

compareBoundaryPoints(how, sourceRange):兩個範圍邊界點進行比較,返回一個數字 -1、0、1。

const range = document.createRange();
range.selectNode(document.querySelector("div"));
const sourceRange = document.createRange();
sourceRange.selectNode(document.getElementsByTagName("div")[1]);
const compare = range.compareBoundaryPoints(Range.START_TO_END, sourceRange);

3.5. comparePoint()

comparePoint(referenceNode, offset):返回-1、0、1具體取決於 是 referenceNode 在 之前、相同還是之後。

const range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
const returnValue = range.comparePoint(document.getElementsByTagName("p").item(0), 1);

3.6. createContextualFragment()

createContextualFragment(tagString):返回一個 DocumentFragment

const tagString = "<div>I am a div node</div>";
const range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
const documentFragment = range.createContextualFragment(tagString);
document.body.appendChild(documentFragment);

3.7. deleteContents()

deleteContents():刪除框選的內容。

const range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
range.deleteContents();

3.8. extractContents()

extractContents():從文檔中刪除範圍內容,並將刪除的內容作為 DocumentFragment 返回。

const range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
const documentFragment = range.extractContents();
document.body.appendChild(documentFragment);

3.9. getBoundingClientRect()

getBoundingClientRect():和 dom 一樣,返回 DOMRect 對象。

const range = document.createRange();
range.setStartBefore(document.getElementsByTagName("em").item(0));
range.setEndAfter(document.getElementsByTagName("em").item(1));
const clientRect = range.getBoundingClientRect();
const highlight = document.getElementById("highlight");
highlight.style.left = `${clientRect.x}px`;
highlight.style.top = `${clientRect.y}px`;
highlight.style.width = `${clientRect.width}px`;
highlight.style.height = `${clientRect.height}px`;

3.10. getClientRects()

getClientRects():返回可迭代的對象序列 DOMRect

const range = document.createRange();
range.selectNode(document.querySelector("div"));
const rectList = range.getClientRects();
const output = document.querySelector("#output");
for (const rect of rectList) {
  output.textContent = `${output.textContent}\n${rect.width}:${rect.height}`;
}

3.11. insertNode()

insertNode(node):在範圍的起始處將 node 插入文檔。

const range = document.createRange();
const newNode = document.createElement("p");
newNode.appendChild(document.createTextNode("New Node Inserted Here"));
range.selectNode(document.getElementsByTagName("div").item(0));
range.insertNode(newNode);

3.12. intersectsNode()

intersectsNode(referenceNode):判斷與給定的 node 是否相交。

const range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
const intersectingNode = range.intersectsNode(
  document.getElementsByTagName("p").item(0),
);

3.13. selectNode()

selectNode(node):設置範圍以選擇整個 node

const range = document.createRange();
const referenceNode = document.getElementsByTagName("div").item(0);
range.selectNode(referenceNode);

3.14. selectNodeContents()

selectNodeContents(node):設置範圍以選擇整個 node 的內容。

const range = document.createRange();
const referenceNode = document.querySelector("div");
range.selectNodeContents(referenceNode);

3.15. setStart()

setStart(startNode, startOffset):設置起點。

const element = document.getElementById("content");
const textNode = element.childNodes[0];
const range = document.createRange();
range.setStart(textNode, 0); // Start at first character
range.setEnd(textNode, 5); // End at fifth character
document.getElementById("log").textContent = range;

3.16. setEnd()

setEnd(endNode, endOffset):設置終點。

const range = document.createRange();
const endNode = document.getElementsByTagName("p").item(3);
const endOffset = endNode.childNodes.length;
range.setEnd(endNode, endOffset);

3.17. setStartBefore()

setStartBefore(node):將起點設置在 node 前面。

const range = document.createRange();
const referenceNode = document.getElementsByTagName("div").item(0);
range.setStartBefore(referenceNode);

3.19. setStartAfter()

setStartAfter(node):將起點設置在 node 後面。

const range = document.createRange();
const referenceNode = document.getElementsByTagName("div").item(0);
range.setStartAfter(referenceNode);

3.19. setEndBefore()

setEndBefore(node):將終點設置為 node 前面。

const range = document.createRange();
const referenceNode = document.getElementsByTagName("div").item(0);
range.setEndBefore(referenceNode);

3.20. setEndAfter()

setEndAfter(node):將終點設置為 node 後面。

const range = document.createRange();
const referenceNode = document.getElementsByTagName("div").item(0);
range.setEndAfter(referenceNode);

3.21. surroundContents()

surroundContents(node):使用 node 將所選範圍內容包裹起來。

const range = document.createRange();
const newParent = document.createElement("h1");
range.selectNode(document.querySelector(".header-text"));
range.surroundContents(newParent);

4. 創建 Range 的方法

4.1. Document.createRange

const range = document.createRange();

4.2. Selection 的 getRangeAt() 方法

const range = window.getSelection().getRangeAt(0)

4.3. caretRangeFromPoint() 方法

if (document.caretRangeFromPoint) {
    range = document.caretRangeFromPoint(e.clientX, e.clientY);
}

4.4. Range() 構造函數

const range = new Range()

5. Range 相容性

image

二、Selection

Selection 對象表示用戶選擇的文本範圍或插入符號的當前位置。它代表頁面中的文本選區,可能橫跨多個元素。

1. 獲取文本對象

window.getSelection()

image

image

2. Selection 術語

2.1. 錨點 (anchor)

錨指的是一個選區的起始點(不同於 HTML 中的錨點鏈接)。當我們使用滑鼠框選一個區域的時候,錨點就是我們滑鼠按下瞬間的那個點。在用戶拖動滑鼠時,錨點是不會變的。

2.2. 焦點 (focus)

選區的焦點是該選區的終點,當你用滑鼠框選一個選區的時候,焦點是你的滑鼠鬆開瞬間所記錄的那個點。隨著用戶拖動滑鼠,焦點的位置會隨著改變。

2.3. 範圍 (range)

範圍指的是文檔中連續的一部分。一個範圍包括整個節點,也可以包含節點的一部分,例如文本節點的一部分。用戶通常下只能選擇一個範圍,但是有的時候用戶也有可能選擇多個範圍。

2.4. 可編輯元素 (editing host)

一個用戶可編輯的元素(例如一個使用 contenteditableHTML 元素,或是在啟用了 designModeDocument 的子元素)。

3. Selection 的屬性

首先要清楚,選擇的起點稱為錨點(anchor),終點稱為焦點(focus)。

  1. anchorNode:選擇的起始節點。

  2. anchorOffset:選擇開始的 anchorNode 中的偏移量。

  3. focusNode:選擇的結束節點。

  4. focusOffset:選擇開始處 focusNode 的偏移量。

  5. isCollapsed:如果未選擇任何內容(空範圍)或不存在,則為 true

  6. rangeCount:選擇中的範圍數,之前說過,除 Firefox 外,其他瀏覽器最多為1。

  7. type:類型:NoneCaretRange

image

image

4. Selection 方法

4.1. addRange()

addRange(range): 將一個 Range 對象添加到當前選區。

const strongs = document.getElementsByTagName("li");
const selection = window.getSelection();
for (var i = 0; i < strongs.length; i++) {
  const range = document.createRange();
  range.selectNode(strongs[i]);
  selection.addRange(range);
}

4.2. collapse()

collapse(node, offset): 將選區摺疊到指定的節點和偏移位置。

const body = document.getElementsByTagName("body")[0];
window.getSelection().collapse(body, 0);

4.3. collapseToEnd()

collapseToEnd(): 將選區摺疊到當前選區的末尾,並把游標定位在原選區的末尾處。

const selection = window.getSelection();
selection.collapseToEnd()

4.4. collapseToStart()

collapseToStart(): 將選區摺疊到當前選區的起始位置,並把游標定位在原選區的最開始處。

const selection = window.getSelection();
selection.collapseToStart()

4.5. containsNode()

containsNode(node, partlyContained): 判斷選區是否包含指定的節點,可以選擇是否部分包含。

window.getSelection().containsNode(document.body, true);

4.6. deleteFromDocument()

deleteFromDocument(): 從文檔中刪除選區內容。

const selection = window.getSelection();
selection.deleteFromDocument();

4.7. empty()

empty(): 從選區中移除所有範圍(同 `removeAllRanges()``,已廢棄)。

const selection = window.getSelection();
selection.empty();

4.8. extend()

extend(node, offset): 將選區的焦點節點擴展到指定的節點和偏移位置。

const selection = window.getSelection();
selection.extend(document.body, 3)

4.9. getRangeAt()

getRangeAt(index): 返回選區中指定索引處的 Range 對象。

const  ranges = [];
const selection = window.getSelection();
for (let i = 0; i < selection.rangeCount; i++) {
  ranges[i] = selection.getRangeAt(i);
}

4.10. removeAllRanges()

removeAllRanges(): 移除所有選區中的範圍。

const selection = window.getSelection();
selection.removeAllRanges();

4.11. removeRange()

removeRange(range): 從選區中移除指定的 Range 對象。

const selection = window.getSelection();
if (selection.rangeCount > 1) {
  for (let i = 1; i < selection.rangeCount; i++) {
    selection.removeRange(selection.getRangeAt(i));
  }
}

4.12. selectAllChildren()

selectAllChildren(node): 選中指定節點的所有子節點。

window.getSelection().selectAllChildren(document.body);

4.13. setBaseAndExtent()

setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset): 設置選區的起始和結束節點及偏移位置。

window.getSelection().setBaseAndExtent(document.getElementById('li1'), 0, document.getElementById('li3'), 1)

4.14. setPosition()

setPosition(node, offset)collapse 的別名

window.getSelection().setPosition(document.body, 0);

5. Selection 相容性

image

到此結束...


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 Web是一種基於互聯網的技術和資源的網路服務系統。它是指由許多互連的電腦組成的全球性電腦網路,使用戶能夠通過瀏覽器訪問和互動式使用各種信息和資源,如網頁、文檔、圖片、視頻、音頻等。通過Web,用戶可以瀏覽網頁、發送電子郵件、參與線上社交網路、進行線上購物等各種活動。Web的核心技術包括 ...
  • 在 recyclerview 中,想要無論滑動到哪,每次按遙控器落焦,需要落焦在左側第一個 item 上面,如果不能觸屏還好,觸屏會導致焦點丟失 根據系統的反饋,如果你滑動了列表,剛好列表的 item 卡在一半的位置,此時系統的落焦規則,不一定會到第一個 之前試過一個效果一般的方案,就是通過 fin ...
  • 在上一篇電腦啟動過程文章中介紹了電腦啟動的基本流程,本篇文章主要介紹Linux內核Kernel的啟動過程。 一、內核啟動的基本流程 sequenceDiagram participant Bootloader participant Kernel participant InitProcess ...
  • title: Vue3使用Composition API實現響應式 date: 2024/5/29 下午8:10:24 updated: 2024/5/29 下午8:10:24 categories: 前端開發 tags: Vue3 Composition Refs Reactive Watch L ...
  • 一、 是什麼 Node作為一門服務端語言,性能方面尤為重要,其衡量指標一般有如下: CPU 記憶體 I/O 網路 CPU 主要分成了兩部分: CPU負載:在某個時間段內,占用以及等待CPU的進程總數 CPU使用率:CPU時間占用狀況,等於 1 - 空閑CPU時間(idle time) / CPU總時間 ...
  • 1️⃣ 原因 由於是一個比較老的項目,所以在做功能時,用到了老項目的一個控制項,這一個控制項是以前封裝好的,依賴的是jquery-1.6.min.js。但是在做下拉框多選功能時,在網上找了一個下拉框多選的框架,但是這個框架依賴是jquery.js(3.7.1),所以才出現了這個問題。 簡單來說就是新老控 ...
  • 1、是什麼 pointer-events 直譯為指針事件,該屬性指定在什麼情況下某個DOM可以成為滑鼠事件的 target。 簡而言之,就是允許/禁止DOM的滑鼠事件(click事件、hover事件、mouse事件等滑鼠事件) 2、具體屬性分析 用法分析:pointer-events: auto | ...
  • 前言 眾所周知,當子組件使用setup後,父組件就不能像vue2那樣直接就可以訪問子組件內的屬性和方法。這個時候就需要在子組件內使用defineExpose巨集函數來指定想要暴露出去的屬性和方法。這篇文章來講講defineExpose巨集函數是如何暴露出去這些屬性和方法給父組件使用。註:本文中使用的vu ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...