客户端激活 (client-side hydration)
所谓客户端激活,指的是 Vue 在浏览器端接管由服务端发送的静态 HTML,使其变为由 Vue 管理的动态 DOM 的过程。
在 entry-client.js
中,我们用下面这行挂载(mount)应用程序:
// 这里假定 App.vue template 根元素的 `id="app"`
app.$mount('#app')
由于服务器已经渲染好了 HTML,我们显然无需将其丢弃再重新创建所有的 DOM 元素。相反,我们需要"激活"这些静态的 HTML,然后使他们成为动态的(能够响应后续的数据变化)。
如果你检查服务器渲染的输出结果,你会注意到应用程序的根元素上添加了一个特殊的属性:
<div id="app" data-server-rendered="true">
data-server-rendered
特殊属性,让客户端 Vue 知道这部分 HTML 是由 Vue 在服务端渲染的,并且应该以激活模式进行挂载。注意,这里并没有添加 id="app"
,而是添加 data-server-rendered
属性:你需要自行添加 ID 或其他能够选取到应用程序根元素的选择器,否则应用程序将无法正常激活。
注意,在没有 data-server-rendered
属性的元素上,还可以向 $mount
函数的 hydrating
参数位置传入 true
,来强制使用激活模式(hydration):
// 强制使用应用程序的激活模式
app.$mount('#app', true)
在开发模式下,Vue 将推断客户端生成的虚拟 DOM 树 (virtual DOM tree),是否与从服务器渲染的 DOM 结构 (DOM structure) 匹配。如果无法匹配,它将退出混合模式,丢弃现有的 DOM 并从头开始渲染。在生产模式下,此检测会被跳过,以避免性能损耗。
一些需要注意的坑
使用「SSR + 客户端混合」时,需要了解的一件事是,浏览器可能会更改的一些特殊的 HTML 结构。例如,当你在 Vue 模板中写入:
<table>
<tr><td>hi</td></tr>
</table>
浏览器会在 <table>
内部自动注入 <tbody>
,然而,由于 Vue 生成的虚拟 DOM (virtual DOM) 不包含 <tbody>
,所以会导致无法匹配。为能够正确匹配,请确保在模板中写入有效的 HTML。