問題背景
項(xiàng)目開發(fā)中,本想把從后臺(tái)獲取到的 meaningVaule
值填充到頁面上捅厂,結(jié)果 html
標(biāo)簽并沒有被處理掉,而是顯示在頁面上了焙贷。如圖所示,html 標(biāo)簽顯示在了瀏覽器中贿堰。
下圖展示的是從后臺(tái)獲取的數(shù)據(jù),含有meaningValue
字段:
問題分析
現(xiàn)在想要的目標(biāo)是:html 標(biāo)簽不要顯示出來庶灿,而是應(yīng)該去規(guī)范 html 文檔的顯示效果,比如遇見<p>
標(biāo)簽則另起一個(gè)段落往踢。
而實(shí)際上呢,瀏覽器端在進(jìn)行DOM
渲染時(shí)峻呕,把形如<
、>
這樣的字符串趣效,解析成了<
、>
英支,繼而把<p>
解析為<p>
這樣的HTML
標(biāo)簽。然后就直接把解析后的字符串直接顯示在了頁面中干花,不再進(jìn)行 html
標(biāo)簽語義分析。由此可以看出池凄,瀏覽器端自己轉(zhuǎn)義了 轉(zhuǎn)移字符
抡驼,這樣的好處很明顯肿仑,可以有效的避免代碼注入攻擊,提升網(wǎng)站的安全原因尤慰。
如此分析一番后,解決的方案也就水落石出了:在瀏覽器DOM
渲染前伟端,先把形如<
、>
這樣的字符串解析成<
责蝠、>
党巾,再把解析后的新的字符串(形如<p>感知和體驗(yàn)...</p>
)進(jìn)行DOM
渲染操作霜医,即可在終端頁面上渲染出最終與其的結(jié)果。
正確的渲染結(jié)果如下圖所示:
解決方案代碼
所謂HTML
編碼肴敛,其實(shí)就是將字符轉(zhuǎn)換為HTML實(shí)體
,這是防止腳本注入攻擊的重要手段之一。
下面的代碼中給出了通用的轉(zhuǎn)義與反轉(zhuǎn)義含有HTML標(biāo)簽的字符串的方法巩搏。
/**
* 把轉(zhuǎn)義后的字符串反轉(zhuǎn)義成含有 html 標(biāo)簽的字符串昨登。
* 示例:
* HTMLDecode("<p>什么是3D打印丰辣?"); // "<p>什么是3D打尤銮俊笙什?"
* @param text
*/
const HTMLDecode = text => {
let tmp = document.createElement('div');
tmp.innerHTML = text;
const output = tmp.innerText || tmp.textContent;
tmp = null;
return output;
}
/**
* 轉(zhuǎn)義含有 html 標(biāo)簽的字符串。
* 示例:
* HTMLEncode("<p>什么是3D打铀銎尽?"); // "<p>什么是3D打油城?"
* @param html
*/
const HTMLEncode = html => {
let tmp = document.createElement('div');
(tmp.textContent != null) ? (tmp.textContent = html) : (tmp.innerText = html);
const output = tmp.innerHTML;
tmp = null;
return output;
}
對(duì)于本篇文章開頭的問題愁憔,在渲染meaningVaule
字符串前腕扶,調(diào)用一下HTMLDecode
方法即可,如下:
const destStr = HTMLEncode(data.meaningValue);
// 再把`destStr`渲染到 DOM 中...
解讀 innerHTML吨掌、innerText、textContent
innerHTML
由于innerText
和textContent
均為對(duì)innerHTML
內(nèi)容作不同的處理而成膜宋,因此我們需要先明確innerHTML
屬性的特點(diǎn)。
賦值操作:
賦值操作秋茫,即先對(duì)值的內(nèi)容進(jìn)行模式匹配棉磨,然后把處理后的值賦予給innerHTML
屬性学辱。模式匹配結(jié)果將導(dǎo)致 保留 和 將字符轉(zhuǎn)換為HTML實(shí)體 兩個(gè)操作。
一. 以下情況將被保留:
- HTML實(shí)體(ASCII實(shí)體策泣、符號(hào)實(shí)體和字符實(shí)體)的實(shí)體名或?qū)嶓w編號(hào);
- 符號(hào)實(shí)體和字符實(shí)體對(duì)應(yīng)的字符萨咕;
- 沒有HTML實(shí)體與之對(duì)應(yīng)的字符;
- HTML標(biāo)簽。(如
<img>
)聪建。
二. 以下情況將會(huì)執(zhí)行字符轉(zhuǎn)換為HTML實(shí)體:
- ASCII實(shí)體對(duì)應(yīng)的字符(<、>金麸、&、'和")挥下。
也就是說除了單獨(dú)的 <揍魂、>棚瘟、&、'和" 會(huì)被轉(zhuǎn)換為實(shí)體名外偎蘸,將原封不動(dòng)地將值賦予給innerHTML屬性。
取值操作:
取值操作迷雪,即直接獲取innerHTML屬性值限书。
innerText & textContent
由于innerText
并非 W3C 標(biāo)準(zhǔn)屬性振乏,尤其是FireFox 45
之前的版本不支持innerText
方法。因此一般情況下可以使用textContent
來代替慧邮,但它兩者是否就能完全等同呢?實(shí)際并非如此误澳!
區(qū)別:取值時(shí) innerText會(huì)把只會(huì)獲取節(jié)點(diǎn)里面的文本信息耻矮,而innerHTML 會(huì)獲取節(jié)點(diǎn)下面的所有標(biāo)簽忆谓。innerHTML是符合W3C標(biāo)準(zhǔn)的屬性,而innerText只適用于IE瀏覽器倡缠,因此,盡可能地去使用innerHTML昙沦,而少用innerText
IE中的innerText是需要對(duì)innerHTML的值進(jìn)行:
- HTML轉(zhuǎn)義(等同于XML轉(zhuǎn)義,對(duì)<盾饮、&等轉(zhuǎn)義字符進(jìn)行處理)采桃;
- 經(jīng)過HTML解釋和CSS樣式解釋;
- 之后又剔除格式信息之后留下的純文本普办。
而FF中的textContent
沒有2、3步衔蹲,在經(jīng)過了HTML轉(zhuǎn)義之后直接剔除所有html標(biāo)簽后得到的純文本肢娘。
總結(jié):
一言以蔽之踪危,這一部分主要涉及到瀏覽器的兼容性問題
猪落。主要思路有以下兩個(gè):
- 可以采用上面給出的
HTMLDecode()
與HTMLDecode()
方法贞远,來進(jìn)行 html 標(biāo)簽的轉(zhuǎn)義與還原處理笨忌。 - 或者,采用
jQuery
中的方法官疲,來抹平掉不同瀏覽器之間的差異性。
可以參考一下:MDN 之 Node.textContent