选择:getComposedRanges() 方法
Selection.getComposedRanges()
方法返回一个 StaticRange
对象数组,表示当前选择范围,并且可以返回可能跨越阴影边界范围的范围。
由于选择范围的端点可能位于阴影树内,甚至位于不同的阴影树内,并且由于这些树可能是封闭的,因此该方法默认情况下无法从阴影树内返回节点。如果该方法需要返回一个包含阴影树内节点的选择,那么这些树的 ShadowRoot
对象必须作为参数传递给该方法。如果未提供相应的根节点,并且选择的起点或终点位于阴影树内,则返回的范围将重新调整范围,以包含阴影根的宿主,而不是根内的某个节点。
返回的范围表示调用 getComposedRanges()
时范围的状态。如果 DOM 或阴影 DOM 发生了变动,则选择范围很可能不正确。应用程序代码可以使用 MutationObserver
来监视 DOM 变动,然后调用 Selection.setBaseAndExtent()
来更新选择。
注意: 当选择可能跨越阴影根边界的范围时,应使用此方法代替 Selection.getRangeAt()
。 Selection.getRangeAt()
不了解阴影根。返回范围未指定,并且在不同浏览器之间有所不同。
语法
getComposedRanges()
getComposedRanges(shadowRoot1)
getComposedRanges(shadowRoot1, shadowRoot2)
getComposedRanges(shadowRoot1, shadowRoot2, /* …, */ shadowRootN)
参数
shadowRoot1
、…、shadowRootN
-
零个或多个
ShadowRoot
参数。如果选择端点位于提供的阴影根之一内,则该范围将能够返回其对应阴影 DOM 树内的节点。否则,如果选择跨越阴影边界,并且未提供相应的ShadowRoot
,则返回的范围将调整为包含阴影根的整个宿主元素。
返回值
一个 StaticRange
对象数组,表示文档的组合(扁平化)树中的选择范围。在编写规范时,该数组预计只包含一个对象。
示例
跨行内阴影根选择
此示例演示了 getComposedRanges()
的行为,包括传递和未传递阴影根的情况,并与 Selection.getRangeAt()
相比。
它允许你选择 DOM 中不同节点(包括开放和封闭阴影根)中定义的文本,使用不同的方法复制选择范围,然后重新应用范围,以查看原始选择的有效性。
HTML
HTML 定义了一些文本节点,其中包含一些 <span>
元素,我们将使用 JavaScript 将阴影根附加到这些元素。我们还添加了一些按钮,用于使用多种不同方法复制和应用选择。
<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");
}
然后,我们创建了一个开放阴影根和一个封闭阴影根,并将它们附加到我们在 HTML 中创建的两个 <span>
元素。这些元素包含一些简单的加粗文本,以便我们可以在 HTML 渲染时轻松识别阴影节点。
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()
获取选择范围。第一个按钮在不传递阴影根的情况下调用 getComposedRanges()
,而第二个按钮传递了两个阴影根。在这两种情况下,组合范围都保存到一个变量中。
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(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 中选择节点到阴影根中。如果你选择 "复制传递阴影根的范围",然后选择 "应用选择" 按钮,你会注意到选择没有改变,因为代码已经提供了对阴影根中所有节点的访问权限,即使它是封闭的。如果你然后选择 "复制不传递阴影根的范围" 按钮,然后应用,选择将扩展到阴影根中的文本末尾。这是因为选择范围被重新调整到宿主节点的末尾,因为 getComposedRanges()
方法没有获得对阴影树内部的可见性。
还可以测试使用 "使用 getRangeAt() 复制范围" 和 "应用选择" 按钮会发生什么。你应该发现,如果跨入阴影根,则选择的范围非常随意,并且在不同的浏览器中有所不同。
规范
规范 |
---|
选择 API # dom-selection-getcomposedranges |
浏览器兼容性
BCD 表只在浏览器中加载
另请参阅
Selection
,它所属的接口。