Selection:getComposedRanges() 方法
Selection.getComposedRanges() 方法返回一個 StaticRange 物件陣列,表示當前選擇的範圍,並且可以返回可能跨越 Shadow DOM 邊界的範圍。
由於選擇範圍的端點可能位於 Shadow DOM 樹內,甚至可能位於不同的 Shadow DOM 樹內,並且這些 Shadow DOM 樹可能是閉合的,因此該方法預設無法返回 Shadow DOM 樹內的節點。如果該方法需要返回包含 Shadow DOM 樹內節點的選區,則必須將這些樹的 ShadowRoot 物件作為引數傳遞給該方法。如果未提供相應的 ShadowRoot,並且選區的開始或結束點位於 Shadow DOM 樹內,則返回的範圍將被重新限定,以包含 ShadowRoot 的宿主元素,而不是 ShadowRoot 內的某個節點。
返回的範圍表示呼叫 getComposedRanges() 時的時間範圍。如果 DOM 或 Shadow DOM 被修改,選定的範圍很可能不正確。應用程式程式碼可以使用 MutationObserver 來監視 DOM 修改,然後呼叫 Selection.setBaseAndExtent() 來更新選區。
注意: 在選擇可能跨越 Shadow DOM 根邊界的範圍時,應使用此方法代替 Selection.getRangeAt()。 Selection.getRangeAt() 不瞭解 Shadow DOM 根。返回的範圍未指定,並且在不同瀏覽器中有所不同。
語法
getComposedRanges()
getComposedRanges(options)
引數
options可選-
一個具有以下屬性的物件,所有屬性都是可選的
shadowRoots可選-
一個
ShadowRoot物件陣列。如果選擇的端點位於提供的 Shadow DOM 根之一內,則範圍將能夠返回其對應的 Shadow DOM 樹內的節點。否則,如果選區跨越 Shadow DOM 邊界但未提供相應的ShadowRoot,則返回的範圍將被調整為包含 Shadow DOM 根的整個宿主元素。
注意: 在原始規範中,Shadow DOM 根被指定為一組 rest 引數。某些瀏覽器可能仍支援此舊語法。
返回值
一個 StaticRange 物件陣列,表示文件組合(已展平)樹中選定的範圍。撰寫本文時,規範期望此陣列僅包含一個物件。
示例
跨內聯 Shadow DOM 根進行選擇
此示例演示了 getComposedRanges() 在傳遞 Shadow DOM 根和不傳遞 Shadow DOM 根時的行為,並與 Selection.getRangeAt() 進行對比。
它允許您選擇定義在不同 DOM 節點中以及開放和閉合 Shadow DOM 根中的文字,使用不同的方法複製選區範圍,然後重新應用該範圍以檢視原始選區效果如何。
HTML
HTML 定義了一些文字節點和一些 <span> 元素,我們將使用 JavaScript 向其附加 Shadow DOM 根。我們還添加了一些按鈕,用於使用多種不同方法複製和應用選區。
<p>
DOM Text One<span id="openHost"></span>DOM Text Two<span
id="closedHost"></span
>DOM Text Three
</p>
<button id="copySelection">Copy range not passing shadow roots</button>
<button id="copySelectionWithShadowRoots">
Copy range passing shadow roots
</button>
<button id="applySelection">Apply selection</button>
<hr />
<button id="copySelectionRangeAt">Copy range with getRangeAt()</button>
<button id="applySelectionGetRangeAt">Apply selection</button>
CSS
CSS 沒有做任何有趣的事情。我們只是將按鈕垂直排列,以便更容易閱讀。
button {
display: block;
}
JavaScript
大部分工作都發生在 JavaScript 中。首先,我們記錄 getComposedRanges() 是否不受支援,儘管我們並沒有阻止示例的其餘部分嘗試使用它。
if (!("getComposedRanges" in Selection.prototype)) {
log("getComposedRanges() method not supported in this browser");
}
然後,我們建立了一個開放和一個閉合的 Shadow DOM 根,並將它們附加到我們在 HTML 中建立的兩個 <span> 元素上。這些元素包含一些簡單的粗體文字,以便在渲染 HTML 時可以輕鬆識別 Shadow DOM 節點。
let openRoot = openHost.attachShadow({ mode: "open" });
openRoot.innerHTML = `<b>Open Shadow DOM Text</b>`;
let closedRoot = closedHost.attachShadow({ mode: "closed" });
closedRoot.innerHTML = `<b>Closed Shadow DOM Text</b>`;
接下來,我們建立程式碼,在單擊前兩個按鈕時使用 getComposedRanges() 獲取選定的範圍。第一個按鈕在不傳遞 Shadow DOM 根的情況下呼叫 getComposedRanges(),第二個按鈕則傳遞了兩個 Shadow DOM 根。在這兩種情況下,組合範圍都會儲存到一個變數中。
const copySelectionButton = document.querySelector("#copySelection");
let composedRangeSelection = null;
copySelectionButton.addEventListener("click", () => {
composedRangeSelection = window.getSelection().getComposedRanges()[0];
log(`Selection copied (no shadow roots passed)`);
});
const copySelectionWithShadowRootsButton = document.querySelector(
"#copySelectionWithShadowRoots",
);
copySelectionWithShadowRootsButton.addEventListener("click", () => {
composedRangeSelection = window
.getSelection()
.getComposedRanges({ shadowRoots: [openRoot, closedRoot] })[0];
log(`Selection has been copied (shadow roots passed)`);
});
下面顯示了“應用選區”按鈕的處理程式。該處理程式呼叫 setBaseAndExtent() 來設定當前選區,傳遞來自儲存範圍的節點和偏移量。
const applySelectionButton = document.querySelector("#applySelection");
applySelectionButton.addEventListener("click", () => {
if (composedRangeSelection) {
window
.getSelection()
.setBaseAndExtent(
composedRangeSelection.startContainer,
composedRangeSelection.startOffset,
composedRangeSelection.endContainer,
composedRangeSelection.endOffset,
);
log(`Selection applied`);
} else {
log(`No selection to apply`);
}
});
程式碼的最後一部分定義了使用 Selection.getRangeAt() 複製當前選區範圍,然後重新應用選區的按鈕。
const copySelectionRangeAtButton = document.querySelector(
"#copySelectionRangeAt",
);
let rangeSelection = null;
copySelectionRangeAtButton.addEventListener("click", () => {
const selection = window.getSelection();
if (selection.rangeCount > 0) {
log(`Selection copied using getRangeAt()`);
rangeSelection = selection.getRangeAt(0);
} else {
log(`No range selected`);
}
});
const applySelectionGetRangeAtButton = document.querySelector(
"#applySelectionGetRangeAt",
);
applySelectionGetRangeAtButton.addEventListener("click", () => {
if (rangeSelection) {
window
.getSelection()
.setBaseAndExtent(
rangeSelection.startContainer,
rangeSelection.startOffset,
rangeSelection.endContainer,
rangeSelection.endOffset,
);
log(`Selection applied`);
} else {
log(`No selection to apply`);
}
});
結果
下面是執行示例。選擇頂部行中的文字,從普通文字開始,到粗體部分結束,這樣您就選擇了從 DOM 到 Shadow DOM 根的節點。如果您選擇“複製範圍(傳遞 Shadow DOM 根)”按鈕,然後單擊“應用選區”按鈕,您會注意到選區沒有改變,因為程式碼可以訪問 Shadow DOM 根中的所有節點,即使它是閉合的。如果您接著選擇“複製範圍(不傳遞 Shadow DOM 根)”按鈕,然後單擊“應用”,則選區將擴充套件到 Shadow DOM 根中所有文字的末尾。這是因為選區被重新限定到了宿主節點的末尾,因為 getComposedRanges() 方法沒有獲得 Shadow DOM 樹內部的可見性。
還可以測試使用“使用 getRangeAt() 複製範圍”和“應用選區”按鈕會發生什麼。您應該會發現,如果您跨入 Shadow DOM 根,選定範圍會相當隨意,並且取決於您使用的瀏覽器。
規範
| 規範 |
|---|
| Selection API # dom-selection-getcomposedranges |
瀏覽器相容性
載入中…
另見
Selection,它所屬的介面。