<head>
在 服务端 render()
hook 中定义 head
标签(如 <title>
或 <meta name="description">
)
我们还可以按页和按组件地定义 head 标签,请参阅以下内容
// /renderer/_default.page.server.js
// Environment: Node.js
import { escapeInject, dangerouslySkipEscape } from "vite-plugin-ssr";
import { renderToHtml } from "some-ui-framework";
export { render };
async function render(pageContext) {
return escapeInject`<html>
<head>
<title>SpaceX</title>
<meta name="description" content="We deliver payload to space.">
</head>
<body>
<div id="root">
${dangerouslySkipEscape(await renderToHtml(pageContext.Page))}
</div>
</body>
</html>`;
}
按页 (静态)
我们可以使用 Custom Export 为指定页面定义 head
标签
// /pages/about.page.js
// 自定义Exports
export const documentProps = {
// title 和 description 会覆盖默认值
title: "About SpaceX",
description: "Our mission is to explore the galaxy.",
};
// /renderer/_default.page.server.js
// Environment: Node.js
import { escapeInject, dangerouslySkipEscape } from "vite-plugin-ssr";
import { renderToHtml } from "some-ui-framework";
export { render };
async function render(pageContext) {
// 自定义Exports可在此处作为 `pageContext.exports.documentProps` 使用
const { documentProps } = pageContext.exports;
// 默认值
const title = documentProps.title || "SpaceX";
const description =
documentProps.description || "We deliver payload to space.";
return escapeInject`<html>
<head>
<title>${title}</title>
<meta name="description" content="${description}">
</head>
<body>
<div id="root">
${dangerouslySkipEscape(await renderToHtml(pageContext.Page))}
</div>
</body>
</html>`;
}
按页 (动态)
我们可以使用 Custom Export 定义动态的 head
标签(运行时确定)
// /pages/rocket.page.route.js
export const '/rocket/@rocketSlug'
// /pages/rocket.page.js
// 自定义Exports
export { getDocumentProps };
function getDocumentProps(pageProps) {
return {
title: pageProps.product.name,
description: pageProps.product.description,
};
}
// /renderer/_default.page.server.js
// Environment: Node.js
export { render };
import { escapeInject, dangerouslySkipEscape } from "vite-plugin-ssr";
import { renderToHtml } from "some-ui-framework";
async function render(pageContext) {
// `pageProps` 由数据获取机制提供,参见 “数据获取” 指南
const { Page, pageProps } = pageContext;
// 自定义Exports可在此处作为 `pageContext.exports.documentProps` 使用
const { getDocumentProps } = pageContext.exports;
// `getDocumentProps()` 可以使用获取的数据来提供页面的元数据
const { title, description } = getDocumentProps(pageProps);
return escapeInject`<html>
<head>
<title>${title}</title>
<meta name="description" content="${description}">
</head>
<body>
<div id="root">
${dangerouslySkipEscape(await renderToHtml(pageContext.Page))}
</div>
</body>
</html>`;
}
按组件
通过一些深度嵌套的视图(React/Vue/...)组件:
- 将
documentProps
添加到 passToClient
- 将
pageContext.documentProps
传递给所有组件,请参考 Guides > Access pageContext
anywhere
- 在深度嵌套的组件中修改
pageContext.documentProps
例子:
// /renderer/_default.page.server.js
// Environment: Node.js
import { escapeInject, dangerouslySkipEscape } from "vite-plugin-ssr";
import renderToHtml from "some-ui-framework";
export async function render(pageContext) {
// 使用 UI 框架将 `pageContext.documentProps` 传递给所有组件
//(如 React Context 或 Vue 的 `app.config.globalProperties`)
const pageHtml = await renderToHtml(
<ContextProvider documentProps={pageContext.documentProps}>
<Page />
</ContextProvider>
);
// 此处发生的是:
// 1. UI 框架将 `documentProps` 传递给所有组件
// 2. (深度嵌套的)组件修改了 `documentProps`
// 3. 将 `documentProps` 渲染到 HTML meta 标签中
return escapeInject`<html>
<head>
<title>${pageContext.documentProps.title}</title>
<meta name="description" content="${
pageContext.documentProps.description
}">
</head>
<body>
<div id="app">
${dangerouslySkipEscape(pageHtml)}
</div>
</body>
</html>`;
}
// 在组件树深处的某个组件中
// 由于之前的步骤,使得我们可以在这里使用 `documentProps`
documentProps.title = "I was set by some deep component.";
documentProps.description = "Me too.";
客户端路由
若使用客户端路由,我们需要确保在页面导航时更新 document.title
:
// /renderer/_default.page.server.js
// Environment: Node.js
// 使 `pageContext.documentProps` 在浏览器环境中可用
export const passToClient = ["documentProps", "pageProps"];
// /renderer/_default.page.client.js
// Environment: Browser
export { render };
function render(pageContext) {
if (!pageContext.isHydration) {
// 页面导航 — 更新网页title
document.title = pageContext.documentProps.title;
}
// ...
}
第三方库
我们也可以使用诸如 @vueuse/head 或 react-helmet 之类的库
我们建议仅当你有以下理由时才使用此类库:
上述解决方案更简单,适用于大多数用例
Head 库已经净化了 HTML <head>
,这意味着我们可以跳过 escapeInject
并使用 dangerouslySkipEscape()
包装整个结果
// /renderer/_default.page.server.js
// Environment: Node.js
import { dangerouslySkipEscape } from "vite-plugin-ssr";
import { renderToHtml } from "some-ui-framework";
export async function render(pageContext) {
return dangerouslySkipEscape(await renderToHtml(pageContext.Page));
}
Markdown
对于使用 markdown 定义的页面,请参考 集成 > Markdown > <head>
(pageContext.exports
)