偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

聊一聊 Vue-SSR 激活失?。╒ue hydration fails)

開(kāi)發(fā) 項(xiàng)目管理
服務(wù)端渲染有很多好處,特別是當(dāng)像 Nuxt.js 或 GridSome 這樣的網(wǎng)站,無(wú)論是使用動(dòng)態(tài) SSR 還是生成靜態(tài)網(wǎng)站,開(kāi)發(fā) Vue-SSR 應(yīng)用程序都是一件輕而易舉的事。

認(rèn)識(shí) Vue-SSR 激活失敗

對(duì)于 SSR 服務(wù)端渲染這個(gè)概念稍有經(jīng)驗(yàn)的開(kāi)發(fā)應(yīng)該都不陌生,官方文檔 Vue SSR 指南 對(duì)于什么是服務(wù)端渲染、為什么使用服務(wù)端渲染以及什么時(shí)候使用服務(wù)端渲染已經(jīng)說(shuō)的很清楚了,結(jié)合一張經(jīng)典的構(gòu)建過(guò)程總結(jié)關(guān)于 SSR 的基本知識(shí)。

1. 基本常識(shí)

什么是服務(wù)端渲染?

  • 客戶端渲染是在瀏覽器中輸出 Vue 組件,進(jìn)行生成 DOM 和操作 DOM,并渲染為 HTML 頁(yè)面展示;
  • 服務(wù)端渲染是將同一個(gè)組件渲染為服務(wù)器端的 HTML 字符串,將它們直接發(fā)送到瀏覽器展示;
  • Vue SSR 則將這些服務(wù)端渲染的靜態(tài) HTML "激活"為客戶端上完全可交互的 HTML 頁(yè)面,服務(wù)端與客戶端渲染的 HTML 混合,體現(xiàn)了 Vue SSR 的一大特性--同構(gòu)。

為什么使用 SSR?

  • 首屏渲染速度快;
  • SEO,服務(wù)端渲染的頁(yè)面內(nèi)容可以被搜索引擎爬蟲(chóng)獲取;

什么場(chǎng)景下使用 SSR?

SSR 服務(wù)端渲染的優(yōu)勢(shì)主要在于首屏渲染與 SEO,那為什么不直接全面推廣使用呢?主要考慮到存在以下劣勢(shì):

  • 代碼復(fù)雜度增加 - 為了實(shí)現(xiàn)前面提到的同構(gòu),應(yīng)用代碼中需要兼容服務(wù)端和客戶端兩種運(yùn)行情況,那么原先只支持瀏覽器環(huán)境運(yùn)行的 API 方法必須增加特殊處理才能在服務(wù)端渲染程序中運(yùn)行;
  • 涉及構(gòu)建設(shè)置和部署有更多要求 - 完全靜態(tài)單頁(yè)面應(yīng)用程序 (SPA) 可以部署在任何靜態(tài)文件服務(wù)器上,而服務(wù)器渲染應(yīng)用程序,需要處于 Node.js server 運(yùn)行環(huán)境;
  • 更多的服務(wù)器負(fù)載 - 在 Node.js 中渲染完整的應(yīng)用程序,

所以是否可以使用服務(wù)端渲染 SSR,需要開(kāi)發(fā)者考慮投入產(chǎn)出比,如果應(yīng)用系統(tǒng)的大多數(shù)頁(yè)面都不需要 SEO,且首屏?xí)r間基本可以滿足需求,使用 SSR 就沒(méi)有必要了。結(jié)合上面的第 2 點(diǎn), SSR 的使用場(chǎng)景:

  • 對(duì)首屏渲染時(shí)間要求高,且盡可能只把首屏內(nèi)容放到服務(wù)端渲染;
  • 對(duì) SEO 要求高的內(nèi)容。

2. 主要痛點(diǎn)問(wèn)題

服務(wù)端渲染有很多好處,特別是當(dāng)像 Nuxt.js 或 GridSome 這樣的網(wǎng)站,無(wú)論是使用動(dòng)態(tài) SSR 還是生成靜態(tài)網(wǎng)站,開(kāi)發(fā) Vue-SSR 應(yīng)用程序都是一件輕而易舉的事。但從另一方面來(lái)講,由于同構(gòu)帶來(lái)的代碼復(fù)雜性與 node 端未知錯(cuò)誤,降低了系統(tǒng)應(yīng)用的穩(wěn)定性與可靠性,并不推薦在非必要場(chǎng)景下使用 SSR 開(kāi)發(fā)。盡管在官方指南的指導(dǎo)下,以及在前人踩坑后提供了變通的解決方案,多數(shù)錯(cuò)誤都可以避開(kāi)或者解決,但仍有未知錯(cuò)誤導(dǎo)致的報(bào)錯(cuò)致使我們無(wú)從下手。

比如我曾在 SSR 服務(wù)端渲染中遇到了一個(gè) Bug,排查了整整 2 個(gè)小時(shí),定位為客戶端渲染失敗,但導(dǎo)致客戶端渲染失敗的原因又有很多。

Error: Error while mounting app: HierarchyRequestError: Failed to execute 'appendChild' on 'Node':
This node type does not support this method. at some-file.js:1

在 SSR 應(yīng)用中不斷踩坑地經(jīng)歷讓我意識(shí)到:大多數(shù)時(shí)候遇到的棘手錯(cuò)誤都是 Vue 客戶端激活失敗導(dǎo)致的。

3. 什么是 Vue 客戶端激活失敗(client-side hydration)客戶端激活

官方指南對(duì) Vue 客戶端激活(client-side hydration)定義很清晰:

所謂客戶端激活,指的是 Vue 在瀏覽器端接管由服務(wù)端發(fā)送的靜態(tài) HTML,使其變?yōu)橛?Vue 管理的動(dòng)態(tài) DOM 的過(guò)程。

這里 hydration,又可以翻譯為“注入”,可以了理解為將在客戶端生成的虛擬 DOM 結(jié)構(gòu)注入到服務(wù)端渲染出的 HTML 中使這些靜態(tài)的 HTML 變?yōu)閯?dòng)態(tài)的。從上面的構(gòu)建過(guò)程圖我們也可以看到,這里的激活發(fā)生在客戶端構(gòu)建完成的包到渲染為 HTML 的過(guò)程中。

客戶端激活失敗

服務(wù)端已經(jīng)渲染好了 HTML,無(wú)需將其丟棄再重新創(chuàng)建所有的 DOM 元素,而是去激活這些渲染好的靜態(tài) HTML,使他們成為動(dòng)態(tài)的以能夠響應(yīng)后續(xù)的數(shù)據(jù)變化。但如果 Vue 客戶端生成的虛擬 DOM 樹(shù)與服務(wù)端渲染的 DOM 結(jié)構(gòu)無(wú)法匹配,就會(huì)發(fā)生客戶端激活失敗。

這里又分為開(kāi)發(fā)模式和生產(chǎn)模式兩種情況:

在開(kāi)發(fā)模式下,如果無(wú)法匹配,它將退出混合模式,丟棄現(xiàn)有的 DOM 并從頭開(kāi)始渲染;

在生產(chǎn)模式下,此檢測(cè)會(huì)被跳過(guò),以避免性能損耗。

這也就能說(shuō)明為什么有些錯(cuò)誤僅在生產(chǎn)模式下才會(huì)出現(xiàn)。

在排查錯(cuò)誤問(wèn)題的過(guò)程中,讀到(谷歌)了一篇關(guān)于 SSR 服務(wù)中客戶端激活失敗梳理較為細(xì)致的文章,列舉出了大多數(shù)可能出現(xiàn)的原因以及解決方案。

原文地址 - What to do when Vue hydration fails

二、正文 - What to do when Vue hydration fails

1. 什么是 Vue 激活失敗

第一次聽(tīng)到"hydration"這個(gè)詞時(shí),它對(duì)我來(lái)說(shuō)非常抽象,我想不出它的意思。最終,我意識(shí)到它并不像一開(kāi)始聽(tīng)起來(lái)那么復(fù)雜:

hydration 是 Vue 轉(zhuǎn)換服務(wù)器端渲染的標(biāo)記并使其具有動(dòng)態(tài)反應(yīng)性的過(guò)程,因此它可以反映來(lái)自 Vue 的動(dòng)態(tài)更改。

如果 Vue 期望與服務(wù)端渲染的 HTML 不同的標(biāo)記,則 hydration 將失敗(也稱為“Vue 將 hydration 丟棄”)。你可以在官方的 Vue SSR 文檔中閱讀更多相關(guān)內(nèi)容。

2. 如何識(shí)別激活失敗

我們現(xiàn)在已經(jīng)意識(shí)到激活是什么和在什么時(shí)候會(huì)失敗,但是我們作為開(kāi)發(fā)者要如何發(fā)現(xiàn)激活沒(méi)有如預(yù)期一般工作呢?

有兩條錯(cuò)誤消息肯定會(huì)指出激活失敗但都有限制條件。

1)第一條是僅在開(kāi)發(fā)環(huán)境中出現(xiàn):Parent:

Parent:  <div class="container"> client-hook-3.js:1:16358
Mismatching childNodes vs. VNodes: NodeList(3) [ p, p, p ] Array [ {} ]

[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content.
This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>.
Bailing hydration and performing full client-side render.

2)第二條錯(cuò)誤消息是僅在生產(chǎn)環(huán)境下使用靜態(tài)生成站點(diǎn)時(shí):

Error: Error while mounting app: HierarchyRequestError: Failed to execute 'appendChild' on 'Node':
This node type does not support this method. at some-file.js:1

眾所周知,激活僅在頁(yè)面首先由服務(wù)端渲染時(shí)發(fā)生,因此通常僅在你應(yīng)用的初始化請(qǐng)求中。

當(dāng)通過(guò)一個(gè)標(biāo)簽導(dǎo)航時(shí)激活失敗是不可見(jiàn)的,僅能在硬重載時(shí)才能復(fù)現(xiàn),這就使得在開(kāi)發(fā)環(huán)境下發(fā)現(xiàn)激活失敗問(wèn)題變得更加困難。

因此激活錯(cuò)誤有時(shí)僅在階段系統(tǒng)或者更糟,僅在生產(chǎn)環(huán)境下被發(fā)現(xiàn)。在極少數(shù)情況下,甚至不會(huì)打印出錯(cuò)誤而僅僅時(shí)某些組件停止工作。

3. 一般引發(fā)錯(cuò)誤的原因

現(xiàn)在我們了解了如何發(fā)現(xiàn)激活錯(cuò)誤,接下來(lái)將研究導(dǎo)致 Vue 激活錯(cuò)誤的典型原因。當(dāng)然這里不可能覆蓋所有可能的原因,因?yàn)檫@些錯(cuò)誤原因差別很大,而且主要取決于代碼。

在以下章節(jié)中,每次提到服務(wù)端渲染,它就與兩種情況都相關(guān)(動(dòng)態(tài) SSR 和靜態(tài)站點(diǎn)生成),因?yàn)閺募夹g(shù)上講,兩者都具有服務(wù)端渲染內(nèi)容(除非另有說(shuō)明)。

1)不合理的 HTML當(dāng)激活失敗發(fā)生時(shí),首先要檢查的應(yīng)該是 HTML 是否合理,官方指南有這類踩坑提示,同時(shí)一般會(huì)有錯(cuò)誤信息提示:


This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>

不幸的是,不合理的 HTML 通常不是激活失敗的原因。不過(guò),你還是應(yīng)該仔細(xì)檢查你的標(biāo)記。

另外,你還要確保檢查縮小設(shè)置,因?yàn)檫^(guò)度的 HTML 縮小可能會(huì)導(dǎo)致無(wú)效的 HTML。

如果你有用戶生成的輸出或來(lái)自 CMS 的內(nèi)容,需要驗(yàn)證此內(nèi)容也是有效的 HTML。

最后,第三方插件或服務(wù)也可能影響和操縱 HTML。后者的一個(gè)常見(jiàn)示例是 Cloudflare,當(dāng)你啟用了它們的服務(wù) -- 如 HTML 縮小,Rocket loader 或其他更改頁(yè)面內(nèi)容的功能時(shí)。

這里有一個(gè)簡(jiǎn)單的示例 codeandbox,其中包含無(wú)效的 HTML 并觸發(fā)了激活失敗。

2)修改 HTML 的腳本關(guān)于腳本:如果向 Vue 應(yīng)用中插入第三方 JS 文件,也可以在 Vue 接收并激活來(lái)自服務(wù)器的 HTML 之前更改 HTML。

3)服務(wù)器和客戶端的狀態(tài)不同服務(wù)器和客戶端上狀態(tài)不一致是發(fā)生激活失敗最常見(jiàn)的原因。像往常一樣,不一致的原因千差萬(wàn)別。

日期、時(shí)間戳和隨機(jī)化

當(dāng)網(wǎng)站包含日期或者時(shí)間戳?xí)r,應(yīng)盡可能小心并使其盡可能靜態(tài),尤其在網(wǎng)站是靜態(tài)生成的情況下。如果客戶端評(píng)估像 new Date() 這樣的表達(dá)式,則該表達(dá)式可能會(huì)與在服務(wù)器上開(kāi)發(fā)階段檢索相同日期時(shí)生成的日期不同。這也讓我對(duì)公司的“關(guān)于”頁(yè)面感到困惑,在該頁(yè)面上,我想根據(jù)當(dāng)前分鐘對(duì)顯示的人員進(jìn)行排序。

export const deterministicRotate = (arr) => {
if (arr.length <= 1) {
return arr
}
const rotations = (new Date()).getMinutes() % arr.length

return rotations ? arr : arr.reverse()
}

如果用戶打開(kāi)頁(yè)面的時(shí)間很奇怪,則計(jì)劃將陣列反轉(zhuǎn)。當(dāng)使用動(dòng)態(tài) SSR 時(shí)效果很好。但當(dāng)切換到靜態(tài)生成的 JAMstack 站點(diǎn)時(shí),該功能就會(huì)成為一個(gè) Bug。你可以在一分鐘后點(diǎn)擊鏈接刷新,會(huì)發(fā)現(xiàn)名字和人正確的交換了,但圖片和原來(lái)一致。糟糕!這是由于服務(wù)器和客戶端時(shí)間不匹配導(dǎo)致的。在移除不確定性代碼后工作恢復(fù)正常。

  • 授權(quán)

不一致的另一個(gè)常見(jiàn)原因是用戶身份驗(yàn)證。這適用于動(dòng)態(tài) SSR 和靜態(tài)站點(diǎn)生成。當(dāng)僅在客戶端(例如,在 localStorage 中)上存儲(chǔ)身份驗(yàn)證狀態(tài)時(shí),服務(wù)器“不知道身份驗(yàn)證”。這將不可避免地導(dǎo)致激活問(wèn)題,因?yàn)榈卿洉r(shí)服務(wù)器和客戶端信息根本不同。因此,如果服務(wù)器不知道正在靜態(tài)生成頁(yè)面的身份驗(yàn)證狀態(tài)**,**則不應(yīng)在服務(wù)器端呈現(xiàn)任何與身份驗(yàn)證相關(guān)的組件。你可能想知道為什么它總是適用于靜態(tài)網(wǎng)站:因?yàn)楫?dāng)生成網(wǎng)站時(shí),它是 HTML,而序列化的代碼是“無(wú)狀態(tài)的”。在構(gòu)建階段,我們無(wú)法考慮“已登錄的用戶狀態(tài)”。這意味著必須從服務(wù)器上的渲染中排除所有與身份驗(yàn)證相關(guān)的組件。

  • 其他原因

除了這兩種情況外,還有更多邊緣情況可能會(huì)打擊你并引起不一致。即使未在此處列出,我們也將解決激活錯(cuò)誤!首先,我們應(yīng)該將其范圍縮小到導(dǎo)致問(wèn)題的 DOM 元素。

4. 解決激活失敗問(wèn)題

1)發(fā)現(xiàn)導(dǎo)致激活失敗的元素我們可以使用您最喜愛(ài)的瀏覽器上的 devTools 縮小問(wèn)題到一個(gè)特定的組件或者 DOM 元素。

  • 確保你在開(kāi)發(fā)環(huán)境下
  • 打開(kāi)開(kāi)發(fā)調(diào)試工具
  • 觸發(fā)激活警告(通常通過(guò)重載網(wǎng)頁(yè))
  • 展開(kāi)[Vue Warn] The client side ...錯(cuò)誤消息查看追蹤堆棧(取決于瀏覽器,也打開(kāi)彈出的 VueJS 列表)
  • 點(diǎn)擊一個(gè)激活回調(diào),將會(huì)打開(kāi) Vue 激活函數(shù)的源代碼
  • 現(xiàn)在,無(wú)論何時(shí)這個(gè)函數(shù)返回 false 都設(shè)置一個(gè) debugger,在撰寫文本時(shí),這種情況發(fā)生了三遍:
if (process.env.NODE_ENV !== 'production') {
if (!assertNodeMatch(elm, vnode, inVPre)) {
return false //HERE
}
}
if (process.env.NODE_ENV !== 'production' &&
typeof console !== 'undefined' &&
!hydrationBailed
) {
hydrationBailed = true;
console.warn('Parent: ', elm);
console.warn('server innerHTML: ', i);
console.warn('client innerHTML: ', elm.innerHTML);
}
return false //HERE
}
 if (process.env.NODE_ENV !== 'production' &&
typeof console !== 'undefined' &&
!hydrationBailed
) {
hydrationBailed = true;
console.warn('Parent: ', elm);
console.warn('Mismatching childNodes vs. VNodes: ', elm.childNodes, children);
}
return false //HERE
}

這同樣允許在激活失敗前檢查激活函數(shù)的參數(shù)。

  • 最后但同樣重要的是,讓激活錯(cuò)誤復(fù)現(xiàn),通常再次重載頁(yè)面是有可能的但有時(shí)更困難
  • 你現(xiàn)在看到觸發(fā)了我們的一個(gè)斷點(diǎn),腳本停止執(zhí)行了
  • 現(xiàn)在打開(kāi)調(diào)試工具的控制臺(tái),在激活失敗的地方寫一個(gè)元素去獲取 DOM 元素。使用 DOM 元素,你將能夠?qū)⒓せ铄e(cuò)誤追溯到你的 Vue 組件之一
  • 繼續(xù)執(zhí)行下一步 PS:這是用戶 budden73對(duì)此 StackOverflow 答案改編后的問(wèn)題定位順序。

2)確保你的 HTML 標(biāo)記合理現(xiàn)在你發(fā)現(xiàn)了導(dǎo)致問(wèn)題的代碼,你首先要做的事確保你的標(biāo)記(也許來(lái)自一個(gè) API)是合理的。像這樣的代碼<p><p>Text</p></p> 無(wú)效,因?yàn)橐粋€(gè)p元素不允許在其中包含其他塊元素(如段落標(biāo)簽)。但是注意,標(biāo)記不允許像

這樣的標(biāo)簽作為子元素,這些標(biāo)記是 Vue 過(guò)渡的默認(rèn)標(biāo)記。你可以通過(guò)<Transition tag="div">進(jìn)行改變。因?yàn)橐粋€(gè)p元素不允許在其中包含其他塊元素(如段落標(biāo)簽)。但是注意,標(biāo)記不允許像

3)解決服務(wù)器與客戶端之間的不一致在 debugger 期間,你能夠從服務(wù)器看到結(jié)果和重新繪制客戶端側(cè)。如果存在不同,你可以看一看,你是如何獲取數(shù)據(jù)和你在服務(wù)端或客戶端渲染了什么。一個(gè)常見(jiàn)的問(wèn)題是靜態(tài)網(wǎng)頁(yè)的認(rèn)證,因?yàn)? HTML 在構(gòu)建時(shí)生成的是無(wú)狀態(tài)的,因此不知道任何授權(quán)狀態(tài),你應(yīng)用的所有和授權(quán)有關(guān)的部分都應(yīng)該在客戶端重新渲染。否則,在客戶端有授權(quán)狀態(tài)的用戶,因?yàn)榈卿浂谕麖姆?wù)端獲取不同的 HTML。然后只剩下一個(gè)方案...

4)最終避免措施:最后一個(gè)解決激活錯(cuò)誤的選擇是完全避免組件出現(xiàn)激活錯(cuò)誤。這對(duì)于在靜態(tài)生成的頁(yè)面上與身份驗(yàn)證相關(guān)的組件來(lái)說(shuō)是必須的,有時(shí)對(duì)于交付你不能更改但必須嵌入的內(nèi)容的組件(例如,來(lái)自第三方應(yīng)用程序)也是必需的。正如我們?cè)谝婚_(kāi)始了解到的,激活僅發(fā)生在組件被同時(shí)渲染在服務(wù)端和客戶端時(shí)。為了避免激活失敗,可以通過(guò)標(biāo)簽避免重新渲染服務(wù)端組件。唯一的缺點(diǎn):該組件不包含在服務(wù)器返回的 HTML 中,對(duì) SEO 沒(méi)有幫助。

5. 總結(jié)

這篇文章結(jié)束了!現(xiàn)在你了解了更多關(guān)于 vue 激活失敗的知識(shí):

  • 什么是激活以及它做了什么?
  • 激活怎么失敗的以及如何發(fā)現(xiàn)激活失敗?
  • 激活失敗的一般原因
  • 如何調(diào)試激活失敗及解決你的應(yīng)用程序

我希望這篇文章很有見(jiàn)解,并且你學(xué)到了一兩件事。你是否遇到了此處未描述的激活錯(cuò)誤原因,或者我錯(cuò)過(guò)了一個(gè)常見(jiàn)原因?隨時(shí)在 Twitter 上或通過(guò)郵件給我發(fā)消息。而且像往常一樣 —— 如果您能宣傳并與同事分享博客文章,我將很高興。

三、踩坑小結(jié)

這篇博客講到了大多數(shù)我在服務(wù)端渲染中遇到的客戶端激活失敗報(bào)錯(cuò)問(wèn)題,甚至也包括了我沒(méi)有遇到的問(wèn)題。當(dāng)然這篇博客也有不足,比如這是 2020 年的文章,其中一些問(wèn)題也許有了新的進(jìn)展,當(dāng)然可能也有許多如我一般的新手還在踩坑。最后整理一下我在開(kāi)發(fā)期間學(xué)習(xí)踩坑所得經(jīng)驗(yàn):

1. 同構(gòu)

因?yàn)槲覀儾捎猛瑯?gòu)的目的是寫一份盡量通用的代碼, 讓它運(yùn)行在兩端。所以我們需要熟悉不同端的運(yùn)行環(huán)境, 至少要熟悉相關(guān) API,Node.js 端是沒(méi)有瀏覽器對(duì)象的, 所以 window, document, DOM 操作都沒(méi)法執(zhí)行。同理, 瀏覽器端是沒(méi)有 process 對(duì)象的,他們各自的 API 實(shí)現(xiàn)也有差別, 這點(diǎn)需要特別留意。還有比較麻煩的就是第三方庫(kù)的引入, 有時(shí)候你并不知道引入的庫(kù)能不能完全運(yùn)行在 Node 端/瀏覽器端,如果它只能運(yùn)行在純?yōu)g覽器環(huán)境, 那可以在 created 階段之后引入和執(zhí)行來(lái)避開(kāi) Node.js 下執(zhí)行。

2. 數(shù)據(jù)預(yù)取問(wèn)題

問(wèn)題:使用 v-html 注入動(dòng)態(tài)獲取的 HTML 內(nèi)容的時(shí)候. 如果 HTML 內(nèi)容有<script>

所包含的 JS 代碼, 會(huì)發(fā)現(xiàn) script 中的事件綁定失效。

分析:其實(shí)在這里頁(yè)面被渲染了兩次, 第一次是發(fā)生在 SSR 直接交給瀏覽器的時(shí)候: 此時(shí)<script>完整被渲染在瀏覽器里, 其內(nèi)容正常執(zhí)行, 事件綁定也正常的綁定在了當(dāng)時(shí)的 DOM 元素上。而第二次渲染時(shí), 走的是 CSR: 在這時(shí)由于是以 v-html 的方式來(lái)渲染替換 HTML, 但是 v-html 實(shí)質(zhì)上是 innerHTML 操作, 這樣<script>雖然會(huì)被替換上去, 但是其中的內(nèi)容不會(huì)執(zhí)行(innerHTML 為安全性考慮而設(shè)計(jì))。所以經(jīng)過(guò)這樣兩次渲染之后, 此時(shí)的 DOM 元素是第二次渲染時(shí)得到的, 而正常執(zhí)行過(guò)的 JS 的事件綁定是綁在在第一次渲染出來(lái)的 DOM 元素上, 這樣就出現(xiàn)了雖然 DOM 存在,但是無(wú)法觸發(fā)該 DOM 上的事件的情況。

解決方法: 將獲取到的 HTML 內(nèi)容進(jìn)行匹配, 剔出<script>內(nèi)容, 無(wú)論第一次或第二次渲染, 只將內(nèi)容交給 v-html 頁(yè)面, 然后單獨(dú)在生命周期 updated(頁(yè)面已將 HTML 內(nèi)容渲染完成)中將<script>創(chuàng)建出來(lái), 添加到頁(yè)面里自動(dòng)執(zhí)行, 實(shí)現(xiàn)綁定。并在下一次頁(yè)面重渲染(可能是頁(yè)面跳轉(zhuǎn)來(lái)到)時(shí)判斷<script>是否存在, 如果真則先刪去再添加, 這樣避免添加多余的<script>塊。

** 那么頁(yè)面為什么會(huì)渲染兩次呢? **

這是由于 Vue SSR 在初始頁(yè)面渲染完成后會(huì)有一次 hydration 過(guò)程, 在這個(gè)過(guò)程中會(huì)照常執(zhí)行流程 mounted 等生命周期。此時(shí)會(huì)判定是否此時(shí)的組件渲染出的內(nèi)容與 SSR 渲染得到的內(nèi)容一致, 如果出現(xiàn)不一致就會(huì)單獨(dú)執(zhí)行一次額外的 CSR(客戶端激活失敗), 以達(dá)到頁(yè)面被能正確地渲染。而因?yàn)槲覀兪褂昧?v-html, 這個(gè)過(guò)程只有在 CSR 時(shí)才會(huì)被執(zhí)行, 所以導(dǎo)致了兩次渲染出來(lái)的內(nèi)容不一致, 觸發(fā)了 Vue SSR 的”補(bǔ)償渲染機(jī)制”, 進(jìn)而執(zhí)行了第二次渲染。

參考文章

  • [Vue SSR 指南] (https://ssr.vuejs.org/zh/guide/hydration.html)
  • [What to do when Vue hydration fails] (https://blog.lichter.io/posts/vue-hydration-error/)
  • [徹底理解服務(wù)端渲染 - SSR 原理 ] (https://github.com/yacan8/blog/issues/30)
  • [Vue.js 服務(wù)端渲染(SSR)不完全指北] (https://lqs469.com/Vue.js%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%B8%B2%E6%9F%93(SSR)%E4%B8%8D%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8C%97/)
  • [從頭開(kāi)始,徹底理解服務(wù)端渲染原理(8 千字匯總長(zhǎng)文)] (https://juejin.cn/post/6844903881390964744#heading-16)
責(zé)任編輯:姜華 來(lái)源: 微醫(yī)大前端技術(shù)
相關(guān)推薦

2021-02-15 15:36:20

Vue框架數(shù)組

2021-02-22 14:04:47

Vue框架項(xiàng)目

2025-02-18 00:00:05

vue后端權(quán)限

2018-06-07 13:17:12

契約測(cè)試單元測(cè)試API測(cè)試

2023-09-22 17:36:37

2021-01-28 22:31:33

分組密碼算法

2020-05-22 08:16:07

PONGPONXG-PON

2020-08-12 08:34:16

開(kāi)發(fā)安全We

2022-11-26 00:00:06

裝飾者模式Component

2020-06-28 09:30:37

Linux內(nèi)存操作系統(tǒng)

2022-10-08 11:33:56

邊緣計(jì)算云計(jì)算

2018-01-10 14:13:04

測(cè)試矩陣API測(cè)試

2019-12-17 10:06:18

CDMA高通4G

2022-03-08 16:10:38

Redis事務(wù)機(jī)制

2020-09-08 06:54:29

Java Gradle語(yǔ)言

2022-03-29 09:56:21

游戲版本運(yùn)營(yíng)

2021-01-01 09:01:05

前端組件化設(shè)計(jì)

2019-02-13 14:15:59

Linux版本Fedora

2021-08-04 09:32:05

Typescript 技巧Partial

2021-01-29 08:32:21

數(shù)據(jù)結(jié)構(gòu)數(shù)組
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)