2

假设以下 DOM 树:

<div id="edit" contenteditable="true">
  this content <a id="link" href="http://www.google.com/">contains</a> a link
</div>

然后在锚点之后创建一个范围:

var r = document.createRange();
var link = document.getElementById('link');
r.setStartAfter(link);
r.setEndAfter(link);

正如预期的那样,它commonAncestorContainer是具有 id 的元素edit

console.log(r.commonAncestorContainer);  /* => <div id="edit" contenteditable="true">…&lt;/div> */

将选择设置为此范围:

var s = window.getSelection();
s.removeAllRanges();
s.addRange(r);

现在查询当前选择范围的窗口并检查其commonAncestorContainer

var r2 = s.getRangeAt(0);
console.log(r2.commonAncestorContainer);

你会发现在 Firefox 中结果和预期的一样;与 id 相同的元素edit

然而,在 WebKit 浏览器中,选择范围的祖先容器突然变成了锚点内的文本节点;"contains",然而当你开始打字时,你会发现你真的不在锚里面。哇!?

单击此处进行现场演示

这种行为背后有什么潜在的理由吗?有什么理由假设它不是 WebKit 错误?

感谢您的 0.02 美元。

4

1 回答 1

1

WebKit 只允许将 DOM 中的某些位置用作选择边界或插入符号位置。因此,它会修改使用选择的addRange()方法选择的范围以符合此要求。另请参阅https://stackoverflow.com/a/14104166/96100

还有另一个问题,那就是 WebKit 在链接末尾有一个插入符号位置的特殊情况,它将键入的文本放置在链接之后而不是链接内部的那个位置。鉴于浏览器将选择报告为在链接内,这无疑是一个令人讨厌的黑客攻击。但是,其他内联元素不会发生这种情况,您可以在修改后的演示版本中看到这一点:

http://jsbin.com/EYoWuWe/7/edit

于 2013-09-03T15:02:24.983 回答