API 参考
useContent()
useContent()
函数用于检索当前路由的最近内容信息。返回的对象包括:
headings: ContentHeading[] | undefined;
menu: ContentMenu | undefined;
headings
数组包含有关 markdown 文件的 <h1>
到 <h6>
html 标题元素 的数据。
菜单是使用 menu.md
文件声明的上下文数据。有关文件格式和位置的更多信息,请参见菜单文件定义。
useDocumentHead()
使用 useDocumentHead()
函数读取文档的头部元数据。
useDocumentHead()
检索只读的 DocumentHead
对象,其中包括:
export interface DocumentHead {
/**
* 表示文档的 `<title>` 元素。
*/
readonly title?: string;
/**
* 用于在头部手动设置 meta 标签。此外,`data` 属性可用于设置任意数据,
* `<head>` 组件稍后
* 可以使用该数据生成 `<meta>` 标签。
*/
readonly meta?: readonly DocumentMeta[];
/**
* 用于在头部手动添加 `<link>` 元素。
*/
readonly links?: readonly DocumentLink[];
/**
* 用于在头部手动添加 `<style>` 元素。
*/
readonly styles?: readonly DocumentStyle[];
/**
* 包含自定义数据的任意对象。当从
* markdown 文件创建文档头部时,不被识别为已知元名称(例如 title、description、author 等)的
* frontmatter 属性将存储在此属性中。
*/
readonly frontmatter?: Readonly<Record<string, any>>;
}
所有的起始器都包含一个 <RouterHead>
组件,该组件负责生成文档的 <head>
元素。它使用 useDocumentHead()
函数检索当前头部元数据并渲染相应的 <meta>
、<link>
、<style>
和 <title>
元素。
import { component$ } from '@builder.io/qwik';
import { useDocumentHead } from '@builder.io/qwik-city';
/**
* RouterHead 组件位于文档的 `<head>` 元素内部。
*/
export const RouterHead = component$(() => {
const head = useDocumentHead();
return (
<>
<title>{head.title}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
{head.meta.map((m) => (
<meta {...m} />
))}
{head.links.map((l) => (
<link {...l} />
))}
{head.styles.map((s) => (
<style {...s.props} dangerouslySetInnerHTML={s.style} />
))}
</>
);
});
useLocation()
使用 useLocation()
函数检索当前位置的 RouteLocation
对象。
useLocation()
允许开发人员了解当前的 URL、参数以及应用程序当前是否正在导航,这对于显示加载指示器很有用。
export interface RouteLocation {
/**
* 从 URL 中提取的路由参数。
*/
readonly params: Record<string, string>;
/**
* 当前的 URL。
*/
readonly url: URL;
/**
* 如果应用程序当前正在导航,则为 true。
*/
readonly isNavigating: boolean;
}
useLocation()
的返回值类似于 document.location
,但在没有全局 location
对象的服务器上使用是安全的,并且它是响应式的,因此可以进行跟踪。
路径路由参数
useLocation()
将路由参数编码为参数。
假设你有:
- 文件:
src/routes/sku/[skuId]/index.tsx
- 用户导航到:
https://example.com/sku/1234
- 然后可以通过
useLocation().params.skuId
检索到skuId
import { component$ } from '@builder.io/qwik';
import { useLocation } from '@builder.io/qwik-city';
export default component$(() => {
const loc = useLocation();
return (
<>
<h1>SKU</h1>
{loc.isNavigating && <p>Loading...</p>}
<p>pathname: {loc.url.pathname}</p>
<p>skuId: {loc.params.skuId}</p>
</>
);
});
上述代码将生成:
<h1>SKU</h1>
<p>pathname: /sku/1234/</p>
<p>skuId: 1234</p>
请注意,
useLocation
是一个只读 API,不应尝试更改返回的loc
对象的值。而是查看useNavigate()
API。
useNavigate()
useNavigate()
函数允许以编程方式导航到下一页,而无需用户点击或导致整个页面重新加载。这是 <Link>
组件内部使用的 API,用于支持 SPA 导航。
此函数返回一个 nav()
函数,可用于“推送”到新路径。
此外,useNavigate
可用于通过调用不带参数的 nav()
函数来刷新当前页面。
import { component$ } from '@builder.io/qwik';
import { useNavigate } from '@builder.io/qwik-city';
export default component$(() => {
const nav = useNavigate();
return (
<>
<button
onClick$={async () => {
// SPA 导航到 /dashboard
await nav('/dashboard');
}}
>
转到仪表板
</button>
<button
onClick$={async() => {
// 刷新页面:不带参数调用
await nav();
}}
>
刷新页面
</button>
</>
);
});
此组件将有一个按钮,当点击时,Qwik City 将导航到 /dashboard
,而不会导致页面重新加载。
请注意,为了 SEO 和可访问性,最好使用
<Link>
组件而不是useNavigate()
以编程方式在某些用户交互后导航到新页面。
routeLoader$()
routeLoader$()
函数用于在给定的页面/中间件或布局中声明新的服务器加载程序。Qwik City 将执行给定路由匹配的所有声明的加载程序。稍后,Qwik 组件可以通过导入它们并调用返回的自定义 hook 函数来检索数据。
import { component$ } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';
export const useGetTime = routeLoader$(async () => {
return { time: new Date() }
});
export default component$(() => {
const signal = useGetTime(); // Signal<{time: Date}>
console.log('Date': signal.value.time);
return (
<div>{signal.value.time.toISOString()}</div>
)
});
请参阅路由加载程序部分了解更多信息。
routeAction$()
routeAction$()
函数用于在给定的页面/中间件或布局中声明新的服务器操作。Qwik City 仅在某些用户交互(例如按钮点击或表单提交)后执行调用的操作。
请参阅服务器操作部分了解更多信息。
<QwikCityProvider>
QwikCityProvider
组件在现有文档中初始化 Qwik City,为 Qwik City 提供必要的上下文,例如 useContent()
和 useLocation()
。
此组件通常位于应用程序的根部,大多数起始器中都可以在 src/root.tsx
文件中找到:
export default component$(() => {
/**
* QwikCity 站点的根始终以 <QwikCityProvider> 组件开始,
* 紧接着是文档的 <head> 和 <body>。
*
* 不要删除 `<head>` 和 `<body>` 元素。
*/
return (
<QwikCityProvider>
<head>
<meta charSet="utf-8" />
<link rel="manifest" href="/manifest.json" />
<RouterHead />
</head>
<body lang="en">
<RouterOutlet />
<ServiceWorkerRegister />
</body>
</QwikCityProvider>
);
});
QwikCityProvider
不会渲染任何 DOM 元素,甚至不会匹配的路由,它只是初始化 Qwik City 核心逻辑,因此不应在同一个应用程序中使用多次。
<RouterOutlet>
RouterOutlet
组件负责在给定时刻渲染匹配的路由,它使用 useContent()
内部渲染当前页面以及所有嵌套的布局。
此组件通常作为 <body>
的子元素,大多数起始器中都可以在 src/root.tsx
文件中找到(参考 QwikCityProvider
的示例)。
<Form>
Form
组件是原生 <form>
元素的包装器,旨在与服务器操作一起使用。
由于此组件使用原生的 <form>
元素,因此它可以在启用或禁用 JavaScript 的任何浏览器中使用。此外,它通过捕获 submit
事件并阻止默认行为来增强原生的 <form>
元素,因此它将像单页应用程序(SPA)而不是完整页面重新加载一样运行。
import { component$ } from '@builder.io/qwik';
import { Form, routeAction$ } from '@builder.io/qwik-city';
// 当表单提交时将调用此操作
export const useLoginAction = routeAction$((data, { cookies, redirect }) => {
if (validate(data.username, data.password)) {
cookies.set('auth', getAuthToken(data.username));
throw redirect(302, '/dashboard');
}
});
export default component$(() => {
const login = useLoginAction();
return (
<Form action={login}>
<input type="text" name="username" />
<input type="password" name="password" />
<button type="submit">登录</button>
</Form>
);
});
<Link>
Link
组件类似于 <a>
锚点元素,但不会导致整个页面重新加载,而是作为单页导航(SPA)进行导航。这在需要导航而不丢失当前状态时非常有用。
请注意,Qwik 中的整页重新加载非常便宜,其他框架滥用 SPA 链接,因为整页重新加载需要 JS 来填充和重新执行所有内容。但 Qwik 不是这样的。我们在内部测试中发现,使用
<a>
通常会导致最流畅的交互。
在幕后,<Link>
组件使用 useNavigate()
API 并阻止原生 <a>
的默认行为:
import { component$ } from '@builder.io/qwik';
import { useNavigate } from '@builder.io/qwik-city';
export const Link = component$<LinkProps>((props) => {
const nav = useNavigate();
return (
<a
preventdefault:click
onClick$={() => {
nav(props.href);
}}
{...props}
>
<Slot />
</a>
);
});
用法
import { component$ } from '@builder.io/qwik';
import { Link } from '@builder.io/qwik-city';
export default component$(() => {
return (
<div>
<a href="/docs" class="my-link">
整页重新加载
</a>
<Link href="/docs" class="my-link">
SPA 导航
</Link>
</div>
);
});