如何让“.innerText”忽略不可见元素的不可见子元素?

Posted

技术标签:

【中文标题】如何让“.innerText”忽略不可见元素的不可见子元素?【英文标题】:How can I make `.innerText` ignore invisible children of an invisible element? 【发布时间】:2017-08-20 23:35:21 【问题描述】:

下面的测试代码结果:

div[0].innerText === "aaaaa zzzzz"
div[1].innerText === "␤aaaaa␤invisible␤zzzzz␤"

如何强制innerTextdiv[1] 提供与div[0] 相同的结果?

我尝试将div[1] 附加到一个临时文档,但由于该文档并未实际显示,因此没有帮助。只有将其附加到字面上可见的文档才有效。

测试代码

var div = [];
div[0] = document.getElementById("visible");
div[1] = div[0].cloneNode(true);

show(0);
show(1);

function show(i) 
    document.getElementById("output").innerhtml += 
      "<p>div[" + i + "].innerText === <code>" + 
      div[i].innerText.replace(/\n/g, "␤") + "</code></p>";
#visible display: block; font-family: sans-serif; font-size: larger; color: red;
code background-color: lightgray; padding: 0 .318em;
<div id="visible">
<span style="display: inline">aaaaa</span>
<span style="display: none">invisible</span>
<span style="display: inline">zzzzz</span>
</div>

<div id="output"></p>

【问题讨论】:

jQuery 可以接受吗? @DineiRockenbach:我认为如果您发布一个 JQuery 答案是为了其他用户的利益是可以的。我会投赞成票,但我只会选择纯 javascript 答案作为解决方案。 【参考方案1】:

只有将它附加到用户真正可见的文档才有效。

但用户不一定必须看到。 :-) 如果你追加它,抓住innerText,然后删除它,用户将永远看不到它:

var div = [];
div[0] = document.getElementById("visible");
div[1] = div[0].cloneNode(true);

show(0);
document.body.appendChild(div[1]);  // *****
show(1);
document.body.removeChild(div[1]);  // *****

function show(i) 
    document.getElementById("output").innerHTML += 
      "<p>div[" + i + "].innerText === <code>" + 
      div[i].innerText.replace(/\n/g, "␤") + "</code></p>";
#visible display: block; font-family: sans-serif; font-size: larger; color: red;
code background-color: lightgray; padding: 0 .318em;
<div id="visible">
<span style="display: inline">aaaaa</span>
<span style="display: none">invisible</span>
<span style="display: inline">zzzzz</span>
</div>

<div id="output"></p>

另外,由于元素不在 DOM 中,因此不能通过 CSS 使其不可见,只能使用内联样式。除了您的display: nonevisibility: hidden(例如,opacity: 0 不会这样做)之外,我想不出任何其他内联样式会使文本从innerText 中排除,所以这很简单排除这些并规范化非pre 元素的空格:

function getInnerText(element) 
  var node, text = "";
  if (element.style.display.toLowerCase() !== "none" && element.style.visibility.toLowerCase() !== "hidden") 
    for (node = element.firstChild; node; node = node.nextSibling) 
      if (node.nodeType === 3) 
        text += node.nodeValue;
       else if (node.nodeType === 1) 
        text += getInnerText(node);
      
    
  
  // Normalize all whitespace if not "pre"
  if (element.tagName !== "PRE" && element.style.whiteSpace.toLowerCase().indexOf("pre") == -1) 
    text = text.replace(/\s+/g, ' ');
  
  return text;

这可能需要调整(我认为它不能正确处理&lt;div&gt;stuff&lt;pre&gt;big gap&lt;/pre&gt;&lt;/div&gt;),但如果您不想使用上面的第一个解决方案,您可以按照这个想法运行...

例子:

var div = [];
div[0] = document.getElementById("visible");
div[1] = div[0].cloneNode(true);

show(0);
document.body.appendChild(div[1]);  // *****
show(1);
document.body.removeChild(div[1]);  // *****

function show(i) 
    document.getElementById("output").innerHTML += 
      "<p>div[" + i + "].innerText === <code>" + 
      getInnerText(div[i]).replace(/\n/g, "␤") + "</code></p>";


function getInnerText(element) 
  var node, text = "";
  if (element.style.display.toLowerCase() !== "none" && element.style.visibility.toLowerCase() !== "hidden") 
    for (node = element.firstChild; node; node = node.nextSibling) 
      if (node.nodeType === 3) 
        text += node.nodeValue;
       else if (node.nodeType === 1) 
        text += getInnerText(node);
      
    
  
  // Normalize all whitespace if not "pre"
  if (element.tagName !== "PRE" && element.style.whiteSpace.toLowerCase().indexOf("pre") == -1) 
    text = text.replace(/\s+/g, " ");
  
  return text;
#visible display: block; font-family: sans-serif; font-size: larger; color: red;
code background-color: lightgray; padding: 0 .318em;
<div id="visible">
<span style="display: inline">aaaaa</span>
<span style="display: none">invisible</span>
<span style="display: inline">zzzzz</span>
</div>

<div id="output"></p>

【讨论】:

如果没有人找到直接的解决方案,我会采用这种解决方法。诚然,并不可怕。 看了这个之后我不得不同意这是最好的。您真正可以做的唯一另一件事是寻找样式属性。但是,如果样式表应用了可见性规则,这无论如何都行不通。 @7vujy0f0hy:我添加了一个替代方案。由于我们不必担心样式表,只需考虑内联样式,并且只有几个会导致文本被遗漏,因此计算内部文本相当简单。 @T.J.Crowder:您的功能看起来令人鼓舞。我想知道它与原生 innerText 算法的兼容性如何。当您想要将实时结果与由不使用您的函数的进程生成的数据库中保存的结果进行比较时,您需要合理的兼容性保证。我曾希望 Javascript 为 innerText 提供一些“虚拟可见性”模式。 @7vujy0f0hy:对于高保真结果,您几乎需要遵从浏览器(上面的第一个解决方案),但要注意不同的浏览器对innerText 有不同的解释。 WHAT-WG 有now specified the property,如果你想充实上面的函数,这很有用,而且 b/c 它鼓励实现收敛于该定义。该定义不在 HTML 规范的 W3C 版本中,但 WHAT-WG (部分)由实际提供现实世界浏览器的供应商组成......

以上是关于如何让“.innerText”忽略不可见元素的不可见子元素?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不更改子元素的情况下更改元素 innerText

如何强制Selenium WebDriver点击当前不可见的元素?

当 Angular 不可用时,如何等到 Protractor 可见元素?

HTML怎么让a是块元素不占一行

如何使用 Chome 和/或 Firefox 上的检查窗口找到网页元素的 innerText 和 outerHTML?

故事板混乱:UITextView 和 UIView 不可见,UITextFields 不可编辑?