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> 元素。

src/components/router-head/router-head.tsx
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
src/routes/sku/[skuId]/index.tsx
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 文件中找到:

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)而不是完整页面重新加载一样运行。

src/routes/login/index.tsx
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 组件类似于 <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>
  );
});

Contributors

Thanks to all the contributors who have helped make this documentation better!

  • manucorporat
  • adamdbradley
  • the-r3aper7
  • nnelgxorz
  • cunzaizhuyi
  • jakovljevic-mladen
  • barbosajlm
  • Eucer
  • eltociear
  • literalpie
  • Mhmdrza
  • ulic75
  • mhevery
  • hamatoyogi