用了這個瀏覽器功能,前端頁面直接崩潰了,咋搞?。?/h1>
你是否遇到過這樣的場景:在瀏覽器中使用谷歌翻譯功能后,網(wǎng)頁突然崩了,控制臺錯誤:

這一切的罪魁禍?zhǔn)?,其?shí)是谷歌翻譯悄悄修改了你的頁面結(jié)構(gòu)!下面就來簡單解釋原因和解決方案。
谷歌翻譯如何“搞破壞”?
我們先看看谷歌翻譯是如何工作的。
下面是未翻譯的文字的 HTML 結(jié)構(gòu):

翻譯之后文字的 HTML 結(jié)構(gòu)是這樣的:

翻譯引擎將純文本節(jié)點(diǎn)包裹在<font>標(biāo)簽中,這種看似無害的操作,卻為現(xiàn)代前端框架埋下了定時炸彈。
兩大致命場景
場景1:狀態(tài)更新失效
對于像React這樣的現(xiàn)代前端框架,它們依賴虛擬DOM來提高性能。當(dāng)組件的狀態(tài)或?qū)傩园l(fā)生變化時,React會基于虛擬DOM的狀態(tài)來操作真實(shí)DOM。然而,當(dāng)真實(shí)DOM被谷歌翻譯修改后,原節(jié)點(diǎn)的位置和狀態(tài)與React的預(yù)期不一致,導(dǎo)致更新操作無法執(zhí)行,頁面因此無法正確更新。
例如,在以下計(jì)數(shù)器組件中:
import React, { useState } from"react";
const Counter = () => {
const [count, setCount] = useState(0);
const increment = () => {
    setCount(count + 1);
  };
const decrement = () => {
    setCount(count - 1);
  };
return (
    <div>
      <h1>example</h1>
      <p>count:{count}</p>
      <p>{count}</p>
      <button onClick={increment}>+1</button>
      <button onClick={decrement}>-1</button>
    </div>
  );
};
exportdefault Counter;在這段代碼中,兩種顯示方式在操作時的結(jié)果完全不同:

可以看到,使用<p>count:{count}</p>顯示時,當(dāng)頁面使用翻譯功能后,點(diǎn)擊按鈕將不會再更新,而<p>{count}</p>在使用谷歌翻譯前后都是正常更新。
- 對于第一種情況:谷歌翻譯將原始文本拆分為多個嵌套的 <font> 節(jié)點(diǎn),破壞了 React 原本控制的文本結(jié)構(gòu)。當(dāng) count 更新時,React 嘗試直接修改原始文本節(jié)點(diǎn)的內(nèi)容,但此時該節(jié)點(diǎn)已被替換為 <font> 節(jié)點(diǎn),導(dǎo)致更新失效。
 - 對于第二種情況:即使谷歌翻譯包裹了 <font> 標(biāo)簽,但 整個 <p> 的唯一子節(jié)點(diǎn)仍然是動態(tài)值 {count} 對應(yīng)的 <font>。React 在更新時可以通過對比虛擬 DOM 發(fā)現(xiàn) <font> 內(nèi)部的文本變化,從而正確更新內(nèi)容。
 
場景2:應(yīng)用崩潰
谷歌翻譯的干擾還可能導(dǎo)致應(yīng)用崩潰。當(dāng)應(yīng)用試圖從DOM中移除一個已被谷歌翻譯修改的文本節(jié)點(diǎn)時,會拋出一個NotFoundError錯誤。這是因?yàn)楫?dāng)應(yīng)用試圖從 DOM 中移除一個條件渲染的文本節(jié)點(diǎn)時,這個節(jié)點(diǎn)已被谷歌翻譯卸載。
下面來看一個例子:
import React, { useState } from "react";
const ToggleText = () => {
  const [showText, setShowText] = useState(true);
  return (
    <div>
      <button onClick={() => setShowText(!showText)}>切換文本</button>
      {showText && "Hello, World!"}
    </div>
  );
};
export default ToggleText;翻譯后的文本被<font>標(biāo)簽包裹后,不再是父元素的直接子節(jié)點(diǎn)。當(dāng)狀態(tài)切換觸發(fā)DOM卸載時,React會因找不到原始節(jié)點(diǎn)而拋出NotFoundError,最終導(dǎo)致組件樹崩潰。
如何解決?
盡管這個問題在 React 社區(qū)中早已被提出,但官方至今都沒有提供完美的解決方案。Dan 給出了一個方法來修復(fù),但是會犧牲一定的性能,需要開發(fā)者根據(jù)實(shí)際情況來權(quán)衡是否有必要添加這段代碼,并且這段代碼也并沒有解決本質(zhì)問題。
圖片
其實(shí),對于上面提到的例子,只需要添加標(biāo)簽來分離文本和動態(tài)內(nèi)容,這樣 React 就不會直接刪除和插入文本節(jié)點(diǎn),就可以避免這個問題。但這只是其中一種情況,我們很難避開所有導(dǎo)致應(yīng)用崩潰的情況。
有以下解決方案可供參考:
- 阻止部分翻譯 :可以通過給需要保持原樣的部分添加 notranslate 屬性來防止谷歌翻譯對其進(jìn)行操作。
 
<p translate="no"></p>- 完全禁用翻譯 :如果希望整個頁面都不被谷歌翻譯,可以在 HTML 頭部加入以下meta標(biāo)簽:
 
<meta name="google" cnotallow="notranslate">- 使用 Error Boundary 隔離錯誤: 對每個組件使用 Error Boundary,防止錯誤擴(kuò)散到整個應(yīng)用,導(dǎo)致應(yīng)用崩潰。
 
<ErrorBoundary>
  <ToggleText />
</ErrorBoundary>- 必要時進(jìn)行國際化:如果應(yīng)用需要支持多種語言,可以考慮實(shí)現(xiàn)應(yīng)用的多語言支持,而不是依賴谷歌翻譯。這樣可以更好地控制文本的顯示和更新,告別第三方翻譯插件的 DOM 污染。
 















 
 
 











 
 
 
 