为啥`Selection.isCollapsed` 在影子 DOM 中总是正确的?

Posted

技术标签:

【中文标题】为啥`Selection.isCollapsed` 在影子 DOM 中总是正确的?【英文标题】:Why is `Selection.isCollapsed` always true in a shadow DOM?为什么`Selection.isCollapsed` 在影子 DOM 中总是正确的? 【发布时间】:2021-10-23 05:11:02 【问题描述】:

根据MDN 和javascript.info,如果有任何当前选定的文本,Selection.isCollapsed 应该是false。对于常规 DOM,这可以按预期工作,但对于影子 DOM,isCollapsed 似乎总是true,即使当前选择了一些文本。有趣的是,在 shadow DOM 中调用 getSelection() 似乎确实正确地返回了当前选择——像 anchorNodeanchorOffset 这样的东西是正确的。但是isCollapsed 始终是true,即使它应该是false

这是一个示例代码框(editor、web view),这是一个代码示例:

document.getElementById("app").innerhtml = "<h1>Hello DOM</h1>";

window.customElements.define(
  "example-component",
  class extends HTMLElement 
    constructor() 
      super();
      const mountPoint = document.createElement("div");
      this.attachShadow( mode: "open" );
      mountPoint.innerHTML = `<h1>hello Shadow DOM</h1>`;
      this.shadowRoot?.appendChild(mountPoint);
    
  
);

document.addEventListener("selectionchange", () => 
  console.log("dom selectionchange");
  console.log(window.getSelection());
  console.log("shadow dom selectionchange");
  console.log(
    document.querySelector("example-component").shadowRoot.getSelection()
  );
);

我使用的是 Chrome 92。

Selection API 和 shadow dom/web 组件似乎确实存在一些问题,但正如我所说,它似乎大部分都在工作,只是这个属性不正确。 p>

【问题讨论】:

【参考方案1】:

所以问题在于 shadowRoot.getSelection() 不是标准 API,仅在基于 Chromium 的浏览器中受支持。并且document.getSelection() 不支持位于影子根内的选择。

目前正在进行扩展选择 API 以支持影子 DOM 的工作,您可以查看当前提案 in this comment 的摘要。如果该提案达成共识,Chrome 可能会弃用 shadowRoot.getSelection() API,因为新的 selection.getComposedRange() API 将取代它。

同时,此处 OP 中的行为似乎是 Chromium 中的一个错误:即使选择来自 shadowRoot.getSelection()isCollapsed 的值也来自 document.getSelection()。我提交了bug for this。鉴于上述工作要进行替换,我不确定它是否会引起太多关注,但也许!

【讨论】:

非常感谢。在此处包含指向相关 caniuse 的链接:caniuse.com/mdn-api_shadowroot_getselection

以上是关于为啥`Selection.isCollapsed` 在影子 DOM 中总是正确的?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 glTranslatef?为啥不直接更改渲染坐标?

为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?

为啥需要softmax函数?为啥不简单归一化?

为啥 g++ 需要 libstdc++.a?为啥不是默认值?

为啥或为啥不在 C++ 中使用 memset? [关闭]

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?