HTML实体置入HTML元素后哪些会被转换为UTF-8字符?
你的问题场景
你在Windows 7的Firefox浏览器中做了一个小工具,想要把文本输入框里的HTML实体代码(比如©)转成对应的UTF-8字符(比如©)。你的实现思路是把输入内容塞进一个隐藏的div,再读取div的内容,但结果发现多数实体能正常转换,可<、>、&、 这些实体却始终保留着代码形式,想搞懂这里面的转换规则。
你的测试代码如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> </head> <body> <input type="text" id="user" onchange="convert()"> <input type="text" id="my_test"> <div id="for_tests"></div> <script> function convert() { var text = document.getElementById('user').value; document.getElementById('for_tests').innerHTML = text; var conv = document.getElementById('for_tests').innerHTML; document.getElementById('my_test').value = conv; } </script> </body> </html>
核心转换规则:为什么有的转有的不转?
这里的关键是HTML解析逻辑和innerHTML的特性,我拆成三类给你讲清楚:
第一类:普通命名实体(非HTML特殊字符)
像©、ü、ç这类实体,对应的是普通的UTF-8字符(©、ü、ç),它们不属于HTML语法里的特殊字符,不会破坏HTML结构。所以当你把它们赋值给div的innerHTML时,浏览器会正常解析成对应的字符;读取innerHTML时,这些字符也不会被转回到实体,直接保留成字符,这就是它们能成功转换的原因。第二类:HTML特殊字符的实体(或它们的转义实体)
HTML里有几个专门用来构建语法的特殊字符:<、>、&、"、',还有不间断空格 。这些字符不能直接出现在HTML源码里(比如<会被当成标签开头),必须用实体来表示(比如<代表<)。
你的测试里输入的&lt;,其实是<的转义(把&转成&)。当你把这个字符串赋值给div的innerHTML时,浏览器先解析第一层:&被转成&,div里的内容变成了<(也就是表示<的实体)。但当你读取innerHTML时,浏览器为了保证HTML源码的合法性,会把任何可能破坏语法的特殊字符转回到实体——这里<里的&是特殊字符,所以会被转成&,最终返回的就是&lt;,看起来像是没转换。
同理,&amp;会被解析成&,读取时又转成&amp;;&nbsp;会被解析成不间断空格,读取时转成 或者&nbsp;(不同浏览器有细微差异)。第三类:数字实体
像⚽这种数字实体,只要对应的字符不是HTML特殊字符,就会被正常解析成字符并保留;如果是特殊字符(比如<对应<),读取innerHTML时同样会被转回到实体。你的测试里⚽能转成对应字符,就是因为它不属于HTML特殊字符。
解决方法:拿到纯文本转换结果
你现在用的是读取div的innerHTML,它返回的是HTML格式的字符串,所以会自动把特殊字符转成实体。如果想要所有实体都转成对应的UTF-8字符,应该读取div的textContent(或者innerText,textContent是更标准的API),它返回的是纯文本内容,不会做任何实体转义。修改你的JS函数即可:
function convert() { var text = document.getElementById('user').value; var testDiv = document.getElementById('for_tests'); testDiv.innerHTML = text; // 用textContent代替innerHTML获取纯文本 var conv = testDiv.textContent; document.getElementById('my_test').value = conv; }
这样不管是&lt;还是&copy;,都会被转成对应的纯文本字符(<和©),完全符合你的需求。
内容的提问来源于stack exchange,提问作者piotr

