getClientRects() 结果在不同浏览器中的差异

Difference in getClientRects() results across browsers

我在我的 JavaScript 函数之一中使用方法 getClientRects() 。该功能在 Chrome、Edge 和 Safari 中正常工作,但在 Firefox 中失败。原因是 getClientRects() 在 Firefox 中的行为不同。

样品可用here in CodePen

var el = document.getElementById('parent');
var range = document.createRange();

range.selectNode(el);
var clientRects = range.getClientRects();
console.log(clientRects);
<div class="parent" id='parent'>
    <div class="child">Bacon ipsum dolor amet meatball bresaola t-bone tri-tip brisket. Jowl pig picanha cupim landjaeger, frankfurter spare ribs chicken. Porchetta jowl pancetta drumstick shankle cow spare ribs jerky tail kevin biltong capicola brisket venison bresaola. Flank sirloin jowl andouille meatball venison salami ground round rump boudin turkey capicola t-bone. Sirloin filet mignon tenderloin beef, biltong doner bresaola brisket shoulder pork loin shankle turducken shank cow. Bacon ball tip sirloin ham.
    </div>
    <div id="info">Click somewhere in the paragraph above</div>
</div>

运行 Chrome 和 Firefox 中的示例以查看差异。这是 Firefox 中的错误吗?

我试图参考文档以获取任何见解,但无法弄清楚。

这确实是一个互操作问题,我打开了一个 issue on the specs 来澄清这一点。

The specs 要求在调用Range#getClientRects()方法时,

For each element selected by the range, whose parent is not selected by the range, include the border areas returned by invoking getClientRects() on the element.

在您的范围中,只有一个元素的父级未按范围select编辑:#parent

所以我们应该得到一个由#parent的DOMRect组成的DOMRectList。对于这一点,所有浏览器都同意,这个元素只有一个这样的 DOMRect:

var el = document.getElementById("parent");
// Element#getClientRects();
var clientRects = el.getClientRects();
console.log(clientRects.length); // 1 everywhere
<div class="parent" id='parent'>
    <div class="child">Bacon ipsum dolor amet meatball bresaola t-bone tri-tip brisket. Jowl pig picanha cupim landjaeger, frankfurter spare ribs chicken. Porchetta jowl pancetta drumstick shankle cow spare ribs jerky tail kevin biltong capicola brisket venison bresaola. Flank sirloin jowl andouille meatball venison salami ground round rump boudin turkey capicola t-bone. Sirloin filet mignon tenderloin beef, biltong doner bresaola brisket shoulder pork loin shankle turducken shank cow. Bacon ball tip sirloin ham.
    </div>
    <div id="info">Click somewhere in the paragraph above</div>
</div>

但是浏览器不同意的地方是第二步。

For each Text node selected or partially selected by the range [...]

Firefox 显然只考虑范围内容第一个可访问的文本节点,而 Chrome 和 Safari 将遍历每个元素以查找这些文本节点。

如果您改为 select 此元素的内容,那么 Firefox 将 return 两个 DOMRects,.child 之一和 #info 之一:

var el = document.getElementById('parent');
var range = document.createRange();
// select the content, not the node itself
range.selectNodeContents(el);
var clientRects = range.getClientRects();
console.log(clientRects.length); // 2 in Firefox
<div class="parent" id='parent'>
    <div class="child">Bacon ipsum dolor amet meatball bresaola t-bone tri-tip brisket. Jowl pig picanha cupim landjaeger, frankfurter spare ribs chicken. Porchetta jowl pancetta drumstick shankle cow spare ribs jerky tail kevin biltong capicola brisket venison bresaola. Flank sirloin jowl andouille meatball venison salami ground round rump boudin turkey capicola t-bone. Sirloin filet mignon tenderloin beef, biltong doner bresaola brisket shoulder pork loin shankle turducken shank cow. Bacon ball tip sirloin ham.
    </div>
    <div id="info">Click somewhere in the paragraph above</div>
</div>

如果你走得更远 select编辑 .child 的内容,你最终会在每个浏览器中每行得到一个框:

var el = document.querySelector('.child');
var range = document.createRange();
// select the content, not the node itself
range.selectNodeContents(el);
var clientRects = range.getClientRects();
console.log(clientRects.length); // all browsers agree, 1 box per line
<div class="parent" id='parent'>
    <div class="child">Bacon ipsum dolor amet meatball bresaola t-bone tri-tip brisket. Jowl pig picanha cupim landjaeger, frankfurter spare ribs chicken. Porchetta jowl pancetta drumstick shankle cow spare ribs jerky tail kevin biltong capicola brisket venison bresaola. Flank sirloin jowl andouille meatball venison salami ground round rump boudin turkey capicola t-bone. Sirloin filet mignon tenderloin beef, biltong doner bresaola brisket shoulder pork loin shankle turducken shank cow. Bacon ball tip sirloin ham.
    </div>
    <div id="info">Click somewhere in the paragraph above</div>
</div>

因此,如果您想要 Chrome 在所有浏览器中的行为,您必须手动遍历每个 Text 节点并一一检索它们的 DOMRect。