将display设置为none后,Div innerText将丢失新行



在编写基于所见即所得HTML的自定义编辑器时,我遇到了这种奇怪的行为。

jsfiddle

在div中输入一些包含新行的文本,其中contentEditable设置为true

此时,div.innerText正好包含包含新行的输入文本。

然后设置div.style.display = none并重新检查div.innerText:它是相同的文本,但新行被删除。

为什么?是否存在";标准行为";对于这种情况?

(在FF开发者版89.0b3(64位(和Chrome版本90.0.4430.85(官方版本((64位

=>跟进还有另一个类似的奇怪问题:

var d = document.getElementById("divTest")
function setup() {
d.innerText = "1n2"
}
function log() {
console.log(d.innerText)
logChildren()
}
function logChildren() {
console.log("Child nodes: ");
d.childNodes.forEach(node => {
console.log(node.toString());
});
}
div[contenteditable] {
border: 1px solid red;
}
<div contenteditable="true" id="divTest"></div>
<input type="button" value="setContent" onclick="setup()"/>
<input type="button" value="log" onclick="log()"/>

单击setContent按钮,然后单击log按钮。输出如预期:

1
2
[object Text]
[object HTMLBRElement]
[object Text]

然后在输入的div中单击。在2后面按enter键转到新行,然后按3。一个得到

1
2
3

在div中,人们会期望在div.innerText中得到相同的结果,但不幸的是:

1
2
3
Child nodes: 
[object Text]
[object HTMLBRElement]
[object HTMLDivElement]
[object HTMLDivElement]

为什么1是[object Text],而2和3是[object HTMLDivElement]?为什么在1和2之间会有空行?等等…

这对我来说毫无意义。

innerText的实现取决于元素是否可见。正如@Nisala在评论中指出的那样,如果将divdisplay属性设置回block,则innerText将再次包含换行符。

const input = document.querySelector("#input");
function performExperiment() {
console.log(`innerText before style change: ${input.innerText}`);

input.style.display = "none";
console.log(`innerText after first style change: ${input.innerText}`);

input.style.display = "block";
console.log(`innerText after second style change: ${input.innerText}`);
}
#input {
border: 1px solid black;
}
<p>Enter multiple lines of text into the box below, then click the button</p>
<div id="input" contenteditable="true"></div>
<button onclick="performExperiment()">Experiment</button>


如果我们查看innerText文档,我们会看到getter行为的第一步定义如下:

  1. 如果没有呈现,或者如果用户代理是非CSS用户代理,则返回其子代文本内容

注意:此步骤可能会产生令人惊讶的结果,因为当对未渲染的元素调用innerTextgetter时,会返回其文本内容,但当对正在渲染的元素进行访问时,会忽略其所有未渲染的子元素的文本内容。

因此,当我们的div没有被渲染时,我们应该期望innerText返回divtextContent。事实上,这就是我们所看到的。

const input = document.querySelector("#input");
function performExperiment() {
input.style.display = "none";
console.log(`innerText: ${input.innerText}`);
console.log(`textContent: ${input.textContent}`);
}
#input {
border: 1px solid black;
}
<p>Enter multiple lines of text into the box below, then click the button</p>
<div id="input" contenteditable="true"></div>
<button onclick="performExperiment()">Experiment</button>


那么,当div可见时,为什么我们的innerText中会出现换行符?文件继续:

  1. 结果成为新的空列表

  2. 对于的每个子节点节点

  1. current是导致使用节点运行内部文本收集步骤的列表结果中的每个项都将是字符串或正整数(需要换行计数(

在这种情况下,innerText将忽略textContent,而是对childNodes列表进行操作。让我们看看这对我们的div:有什么价值

const input = document.querySelector("#input");
function performExperiment() {
input.childNodes.forEach(node => {
console.log(node.toString());
});
}
#input {
border: 1px solid black;
}
<p>Enter multiple lines of text into the box below, then click the button</p>
<div id="input" contenteditable="true"></div>
<button onclick="performExperiment()">Experiment</button>


如您所见,按下ENTER键,通过将div添加到div的childNodes列表,将新行添加到div的内容中。为什么会出现这种情况超出了这个问题的范围,但就其本身而言,这将是一个很好的问题。

如果您正在使用页面内编辑器,HTML规范中有一部分包含最佳实践。


回顾:

如果div可见,则innerTextgetter使用divtextContent属性。

如果div不可见,则对childNodes树中的每个节点执行内部文本收集步骤,并将结果连接在一起。

当为我们的div计算innerText的值时,display属性的值很重要,因为它决定了是使用textContent属性还是使用childNodes树的评估。


注意:@Domino的回答中有更多信息。

相关内容

  • 没有找到相关文章

最新更新