lmk123 / blog

个人技术博客,博文写在 Issues 里。
https://github.com/lmk123/blog/issues
623 stars 35 forks source link

textContent 与 innerText 的区别 #93

Open lmk123 opened 2 years ago

lmk123 commented 2 years ago

在今天之前,我一直认为 textContentinnerText 是等价的,只不过前者是标准的,后者是非标准的。所以,我一直以来都使用 textContent 读取一个元素的文本内容。

但是,今天遇到了一个 bug 让我发现,这两者是有区别的,而且,某些情况下,innerText 更适用一些。

先说说 bug

这个 bug 出在划词翻译当中,先看图:

image

这段英文出自 https://github.com/websockets/ws,图中的英文段落是一个 p 元素,划词翻译的全文翻译功能会读取这个元素的 textContent 并将翻译结果显示在下方。这个 bug 就在于,我发现翻译结果不太准确,而且有一些地方有不易察觉的空格,注意图中的“该扩展使 客户端”,其中“使”和“客”中间有一个空格。

在经过一番调试,我发现 p.textContent 读取出来的英文文本 which enables the client 的 enables 和 the 中间的不是空格,而是一个换行符 \n

从视觉上看这应该是一个空格,但 textContent 却读取出来了换行符,导致划词翻译将一句话拆分成了两句话进行翻译,所以翻译结果就不准确了。

我谷歌了一下 textContent 为什么会有换行符,但得到的搜索结果都讲的是如何在 textContent 里加换行符,只有一条链接引起了我的注意:What's Best: innerText vs. textContent

抱着试一试的想法,我试了一下 p.innerText,它返回的就是正常的空格——这一刻我被惊讶到了:原来 textCotentinnerText 不是等价的!

innerTexttextContent 的不同之处

为了知道为什么 innerText 的内容里不包含空格,我查了一下这两者的不同点。我主要看了以下两个链接:

总结如下:

回到开头的英文段落

再回到文章开头的那个段落,为什么视觉上的空格其实是一个换行符?我在 README.md 里找到了答案。

在 Markdown 里,这里确实是有换行的:

.....................which enables
the client........................

然后这个段落被渲染成 HTML 之后是这样的:

<p>
.....................which enables
the client........................
</p>

浏览器在渲染这个 p 元素时,会把换行符显示成空格,这也就导致了视觉上的空格其实是换行符的问题。

innerText 更适合划词翻译的全文翻译场景

由于 innerText 的性能问题,前面提到的文章建议使用 textContent 替代 innerText。但是,在划词翻译的全文翻译场景下,用 innerText 更合适——因为它不会读取出来不可见的文本。

之前就有用户反馈过这个问题:全文翻译会出现额外的字符翻译,这个问题其实就是不可见的元素被 textContent 读取出来然后也翻译了。我本来还打算自己写一个方法用于去掉不可见元素,但现在直接换成 innerText 就可以了。至于性能方面,实际使用起来完全没觉得比 textContent 慢。

最后,还有一个需要注意的点:如果元素本身就是一个不可见元素,那么 innerTexttextContent 的内容是一样的。