这两天正在把 CodeMirror 融入 编辑器。。。结果发现了奇怪的现象: textarea 内正常的换行居然变成了<br>
以前从未出现过这种事情,难道是 Chrome 57(最新版)出现了 bug?
找了一下 FireFox 居然是这样, 再看 Chrome 49 还是这样。。。
看来不是最新版的问题,还是在自己的代码中找原因吧....
首先要了解 textarea 操作的几个特性:
- 对于现在最新版的浏览器中 innerHTML / innerText / textContent 这几个方法都可以操作 textarea 内容
- 对于旧版的浏览器中 FireFox 是不能使用 innerText 方法的(现在就不管这个了)
- 一旦针对 textarea 使用了 value 方法 或 用户在 textarea 内输入内容后, innerHTML / innerText / textContent 这几个方法都不会影响 textarea 看到的值,当然也不会影响 value 的数据了
之前操作 textarea 部分的代码如下:
// 这是在保存编辑内容时,为了把 textarea 的内容正确保存时,必须要把 value 赋值给 html 内
// 为了处理 旧版 Firefox 兼容
textType = (obj.innerText === undefined ? 'textContent' : 'innerText');
if (obj.value !== obj[textType]) {
obj[textType] = obj.value;
}
于是立刻找到问题所在:innerText
在编辑器内对于 textarea 只要使用 innerText 设置的值,'\n' 全部都会变成 '<br>'
不可思议的情况:
为什么以前从来没有发现过这个问题?? 为了谨慎着手,制作一个干干净净的 html 页面,只有一个 textarea,使用 innerText 设置数据,居然全都正常了。。OMG,难道是 CodeMirror 的 bug??赶紧打开 CodeMirror 提供的 Demo,直接操作对应的 textarea 全都出现 <br>!!看看源码吧, CodeMirror 内没有什么 innerText 相关的代码。。。太奇怪了吧??沉思中。。。
剧情反转:
最后只有终极法宝了,把出现问题的页面删除 script、删除 style,删除多余的,只留下 textarea,问题依然存在,然后创建一个新的 textarea,innerText 操作正常。这时恍然大悟,两个 textarea 唯一的区别就是 'display:none'
<textarea id="t01" style="display:none"></textarea>
<textarea id="t02" style="visibility:hidden"></textarea>
<textarea id="t03" ></textarea>
针对这 3 个 textarea 做如下测试:
document.querySelector('#t01').innerText = '555\n666';
document.querySelector('#t02').innerText = '555\n666';
document.querySelector('#t03').innerText = '555\n666';
可以看到 只有 display 为 none 的时候,数据出现了异常:
这样导致的直接错误是,获取整个 body 的 html时, textarea 内的数据异常了:“<textarea id="t01" style="display:none">555<br>666</textarea>”,这个 <br> 会直接导致编辑内容重新展示时出现异常。
不过对于 innerHTML 、textContent 操作均未发现异常。
问题解决:
找到了病根儿就好办了,针对这种情况调整一下代码即可:
textType = (obj.textContent === undefined ? 'innerText' : 'textContent');
if (obj.value !== obj[textType]) {
obj[textType] = obj.value;
}
反思:
绝大部分界面操作都是直接让用户直接在 textarea 内输入,保存时从 textarea 的 value 内获取数据,像我们这种把编辑器内再融入 CodeMirror 的情况是很少见的,我可以尝试去 chrome 上提交一下 bug,看看是否能得到什么回复。。。拭目以待
https://bugs.chromium.org/p/chromium/issues/detail?id=705478
大结局再次反转:
Chrome 的技术人员答复了我提交的 bug
原文如下:
Safari and Firefox has the same behavior.
This behavior is defined by the HTML standard. The behavior without display:none is a bug according to it.
https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attribute:dom-innertext-3
Please use textContent or defaultValue or value setter instead of innerText setter.
说白了,早先 innerText 是 IE 自己搞的,现在已经进入到 HTML 标准中,而且定义了是会把 \n 变成 <br> 的,反倒是 没有 display:none 时,我们之前认为正确的结果是个 bug(我估计可能是为了不影响长久以来已经约定俗成的结果)。
备注:测试了一下 <pre> 效果与 <textarea> 完全一样。
综上所述,面对未来的浏览器,更加严谨规范的操作 DOM,innerText 要根据你的场景来使用了,对于 <pre> 和 <textarea> 来说尽量使用 textContent / value 方法去操作吧。