meta
meta
匯出允許您為應用程式中的每個路由新增中繼資料 HTML 標籤。這些標籤對於搜尋引擎最佳化 (SEO) 和瀏覽器指令以決定某些行為非常重要。它們也可以被社群媒體網站用來顯示您應用程式的豐富預覽。
meta
函式應傳回 MetaDescriptor
物件的陣列。這些物件與 HTML 標籤一一對應。因此,這個 meta 函式
export const meta: MetaFunction = () => {
return [
{ title: "Very cool app | Remix" },
{
property: "og:title",
content: "Very cool app",
},
{
name: "description",
content: "This app is the best",
},
];
};
產生這個 HTML
<title>Very cool app | Remix</title>
<meta property="og:title" content="Very cool app" />;
<meta name="description" content="This app is the best" />
預設情況下,中繼描述符在大多數情況下會呈現一個 <meta>
標籤。兩個例外是
{ title }
呈現一個 <title>
標籤{ "script:ld+json" }
呈現一個 <script type="application/ld+json">
標籤,其值應為可序列化的物件,該物件會被字串化並注入標籤中。export const meta: MetaFunction = () => {
return [
{
"script:ld+json": {
"@context": "https://schema.org",
"@type": "Organization",
name: "Remix",
url: "https://remix.dev.org.tw",
},
},
];
};
中繼描述符也可以透過將 tagName
屬性設定為 "link"
來呈現一個 <link>
標籤。這對於與 SEO 相關的 <link>
標籤(例如 canonical
URL)很有用。對於樣式表和網站圖示等資產連結,您應該改用links
匯出。
export const meta: MetaFunction = () => {
return [
{
tagName: "link",
rel: "canonical",
href: "https://remix.dev.org.tw",
},
];
};
meta
函式參數location
這是目前的路由器 Location
物件。這對於在特定路徑或查詢參數產生路由的標籤很有用。
export const meta: MetaFunction = ({ location }) => {
const searchQuery = new URLSearchParams(
location.search
).get("q");
return [{ title: `Search results for "${searchQuery}"` }];
};
matches
這是目前路由匹配的陣列。您可以存取許多資訊,特別是來自父匹配的 meta 和 data。
matches
的介面類似於 useMatches
的返回值,但每個匹配都將包含其 meta
函數的輸出。這對於在路由層次結構中合併元數據很有用。
data
這是來自您路由的 loader
的資料。
export async function loader({
params,
}: LoaderFunctionArgs) {
return json({
task: await getTask(params.projectId, params.taskId),
});
}
export const meta: MetaFunction<typeof loader> = ({
data,
}) => {
return [{ title: data.task.name }];
};
params
路由的 URL 參數。請參閱路由指南中的動態區段。
error
觸發錯誤邊界的拋出錯誤將會傳遞到 meta
函數。這對於產生錯誤頁面的元數據很有用。
export const meta: MetaFunction = ({ error }) => {
return [{ title: error ? "oops!" : "Actual title" }];
};
除了目前路由的資料外,您通常還會想要存取路由層次結構中較高層級的路由資料。您可以在 matches
中透過其路由 ID 進行查找。
import type { loader as projectDetailsLoader } from "./project.$pid";
export async function loader({
params,
}: LoaderFunctionArgs) {
return json({ task: await getTask(params.tid) });
}
export const meta: MetaFunction<
typeof loader,
{ "routes/project.$pid": typeof projectDetailsLoader }
> = ({ data, matches }) => {
const project = matches.find(
(match) => match.id === "routes/project.$pid"
).data.project;
const task = data.task;
return [{ title: `${project.name}: ${task.name}` }];
};
meta
與巢狀路由的陷阱由於多個巢狀路由同時渲染,因此需要進行一些合併才能確定最終渲染的 meta 標籤。Remix 讓您可以完全控制此合併,因為沒有明顯的預設值。
Remix 將會採用最後一個匹配的具有 meta 輸出的路由並加以使用。這允許您覆寫諸如 title
之類的內容、移除父路由新增的諸如 og:image
之類的內容,或保留父路由的所有內容並為子路由新增新的 meta。
當您剛開始接觸時,這可能會變得非常棘手。
考慮像 /projects/123
這樣的路由,可能會有三個匹配的路由:app/root.tsx
、app/routes/projects.tsx
和 app/routes/projects.$id.tsx
。所有三個路由都可能輸出 meta 描述符。
export const meta: MetaFunction = () => {
return [
{
name: "viewport",
content: "width=device-width,initial-scale=1",
},
{ title: "New Remix App" },
];
};
export const meta: MetaFunction = () => {
return [{ title: "Projects" }];
};
export const meta: MetaFunction<typeof loader> = ({
data,
}) => {
return [{ title: data.project.name }];
};
使用此程式碼,我們將會在 /projects
和 /projects/123
遺失 viewport
meta 標籤,因為只使用最後一個 meta,並且該程式碼不會與父元素合併。
meta
幾乎每個應用程式都會有像 viewport
和 charSet
這樣的全域 meta。我們建議在 根路由 中使用一般的 <meta>
標籤,而不是 meta
輸出,這樣您就不需要處理合併的問題。
import {
Links,
Meta,
Outlet,
Scripts,
} from "@remix-run/react";
export default function App() {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1"
/>
<Meta />
<Links />
</head>
<body>
<Outlet />
<Scripts />
</body>
</html>
);
}
meta
您還可以透過簡單地不輸出您想要從父路由覆寫的 meta
來避免合併問題。不要在父路由上定義 meta
,而是使用索引路由。這樣您就可以避免針對標題等內容進行複雜的合併邏輯。否則,您需要找到父標題描述符,並將其替換為子標題。透過使用索引路由來避免需要覆寫,會容易得多。
meta
合併通常您只需要將 meta
新增到父路由已定義的內容。您可以使用展開運算符和 matches
參數來合併父 meta
export const meta: MetaFunction = ({ matches }) => {
const parentMeta = matches.flatMap(
(match) => match.meta ?? []
);
return [...parentMeta, { title: "Projects" }];
};
請注意,這不會覆寫諸如 title
之類的內容。這只是附加性的。如果繼承的路由 meta 包含 title
標籤,您可以使用 Array.prototype.filter
來覆寫。
export const meta: MetaFunction = ({ matches }) => {
const parentMeta = matches
.flatMap((match) => match.meta ?? [])
.filter((meta) => !("title" in meta));
return [...parentMeta, { title: "Projects" }];
};
meta
合併輔助程式如果您無法透過全域 meta 或索引路由來避免合併問題,我們建立了一個輔助程式,您可以將其放入您的應用程式中,以便輕鬆覆寫和附加到父 meta。