vue teleport 在 ssr 中默认跳过内容,需服务端注入目标 html 并客户端预置容器和 __teleport 数据以确保 hydration 一致。

Vue Teleport 在服务端渲染(SSR)中默认不执行传送逻辑,内容会被跳过,必须手动干预才能保证客户端挂载一致。
SSR 中 Teleport 默认行为
Vue 3 的 SSR 渲染器在生成 HTML 字符串时,遇到 Teleport 节点会直接忽略其子内容,既不序列化到输出 HTML 中,也不保留占位信息。这意味着:
- 模态框、提示层等 Teleport 内容在首屏 HTML 中完全缺失
- 客户端 hydration 时,目标容器(如
body或#modal-root)可能已存在,但 Teleport 子节点无对应 DOM,导致首次 patch 失败或警告 - 服务端无法预渲染 Teleport 内容,影响 SEO 和首屏可访问性(对纯展示型弹窗类组件影响较大)
正确处理的两个关键步骤
要让 Teleport 在 SSR 场景下“可 hydrate、可复用、不报错”,需同时满足服务端注入 + 客户端匹配:
-
服务端:显式收集并注入 Teleport 内容
使用renderToString(app)或renderToNodeStream(app)后,通过app._context.teleports(内部 API,非公开但稳定)或更推荐的createSSRApp+ 自定义插件方式,提取所有 Teleport 的子 vnode,并按to属性归类,拼接到对应目标容器的 HTML 片段中 -
客户端:启用 hydration 并确保目标容器就位
在挂载前,手动将 Teleport 目标容器(如<div id="modal-root"></div>)插入document.body;同时在根应用创建时传入__teleport字段(Vue 官方 SSR 文档推荐方式),告知 hydration 过程哪些节点属于 Teleport 内容
实际操作建议
避免直接依赖内部属性,推荐采用 Vue 官方认可的模式:
- 在服务端入口(如
entry-server.js)中,调用renderToString(app)前,先遍历组件树收集所有 Teleport 节点,将其子内容字符串化后,追加到对应目标容器的 HTML 中(例如把to="body"的内容直接 append 到末尾) - 在客户端入口(
entry-client.js),确保目标容器 DOM 已存在:if (!document.getElementById("modal-root")) {<br> const el = document.createElement("div");<br> el.id = "modal-root";<br> document.body.appendChild(el);<br>} - 使用
createApp时传入预置的__teleport数据(通常由服务端注入到 window 上),使客户端渲染器能识别并跳过重复挂载
注意事项
几个容易出错的细节:
- 目标容器必须在
createApp().mount()之前存在于 DOM 中,否则客户端 patch 阶段找不到target,会静默丢弃内容或报 warning - 多个 Teleport 指向同一容器时,服务端需保持与客户端相同的渲染顺序,否则 hydration key 不匹配导致 DOM 错乱
-
disabled属性在 SSR 中不会生效——服务端只看to是否为有效值,:disabled是运行时逻辑,需客户端二次控制
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










