Qwik City 的核心功能有哪些?
Qwik City 是 Qwik 的全栈框架,提供了完整的路由、数据获取和服务端功能。以下是 Qwik City 的核心概念和使用方法:1. Qwik City 简介Qwik City 构建在 Qwik 之上,提供了:基于文件系统的路由服务端数据加载表单处理和验证中间件支持SEO 优化国际化支持2. 路由系统文件系统路由Qwik City 使用基于文件系统的路由,文件结构直接映射到 URL:src/├── routes/│ ├── index.tsx -> /│ ├── about/│ │ └── index.tsx -> /about│ ├── products/│ │ ├── index.tsx -> /products│ │ └── [id]/│ │ └── index.tsx -> /products/:id│ └── layout.tsx -> 全局布局动态路由// routes/products/[id]/index.tsximport { component$ } from '@builder.io/qwik';import { routeLoader$ } from '@builder.io/qwik-city';import { useLocation } from '@builder.io/qwik-city';export const useProductData = routeLoader$(async ({ params, url, env }) => { const response = await fetch(`https://api.example.com/products/${params.id}`); return response.json();});export default component$(() => { const product = useProductData(); const location = useLocation(); return ( <div> <h1>{product.value.name}</h1> <p>{product.value.description}</p> <p>Price: ${product.value.price}</p> </div> );});嵌套路由// routes/layout.tsximport { component$, Slot } from '@builder.io/qwik';export default component$(() => { return ( <div> <header>Header</header> <main> <Slot /> </main> <footer>Footer</footer> </div> );});3. 数据加载routeLoader$ - 服务端数据加载import { routeLoader$ } from '@builder.io/qwik-city';export const useUserData = routeLoader$(async ({ params, url, env, requestEvent }) => { // 访问请求参数 const userId = params.id; // 访问 URL 查询参数 const searchParams = url.searchParams; const page = searchParams.get('page'); // 访问环境变量 const apiKey = env.get('API_KEY'); // 访问请求事件 const cookie = requestEvent.cookie.get('session'); const response = await fetch(`https://api.example.com/users/${userId}`); return response.json();});clientLoader$ - 客户端数据加载import { clientLoader$ } from '@builder.io/qwik-city';export const useClientData = clientLoader$(async ({ params, navigate }) => { // 客户端数据获取 const response = await fetch(`/api/data/${params.id}`); return response.json();});useResource$ - 组件级数据加载import { component$, useResource$ } from '@builder.io/qwik';export const UserList = component$(() => { const users = useResource$(({ track, cleanup }) => { // 追踪依赖 track(() => /* 依赖项 */); // 清理函数 cleanup(() => { // 清理逻辑 }); return fetch('https://api.example.com/users'); }); return ( <div> {users.value ? ( <ul> {users.value.map(user => <li key={user.id}>{user.name}</li>)} </ul> ) : ( <p>Loading...</p> )} </div> );});4. 表单处理action$ - 服务端表单处理import { action$, zod$, z } from '@builder.io/qwik-city';import { component$, Form } from '@builder.io/qwik-city';// 定义表单验证export const useContactForm = action$(async (data, { requestEvent }) => { // 服务端处理逻辑 const { name, email, message } = data; // 发送邮件 await sendEmail({ name, email, message }); return { success: true };}, zod$({ name: z.string().min(2), email: z.string().email(), message: z.string().min(10)}));export default component$(() => { const action = useContactForm(); return ( <Form action={action}> <input name="name" placeholder="Name" /> <input name="email" type="email" placeholder="Email" /> <textarea name="message" placeholder="Message"></textarea> <button type="submit">Submit</button> {action.value?.success && <p>Message sent!</p>} </Form> );});clientAction$ - 客户端表单处理import { clientAction$ } from '@builder.io/qwik-city';export const useClientAction = clientAction$(async (data) => { // 客户端处理逻辑 console.log('Client action:', data); return { success: true };});5. 中间件请求中间件// routes/middleware.tsimport { middleware$ } from '@builder.io/qwik-city';export const onRequest = middleware$(async ({ requestEvent, next }) => { // 请求前处理 const url = requestEvent.url; const cookie = requestEvent.cookie.get('session'); if (!cookie && url.pathname !== '/login') { throw requestEvent.redirect(302, '/login'); } return next();});export const onResponse = middleware$(async ({ requestEvent, next }) => { // 响应后处理 const response = await next(); // 添加响应头 response.headers.set('X-Custom-Header', 'value'); return response;});6. SEO 优化元数据设置import { component$ } from '@builder.io/qwik';import { routeLoader$, useDocumentHead, useLocation } from '@builder.io/qwik-city';export const useProductData = routeLoader$(async ({ params }) => { const response = await fetch(`https://api.example.com/products/${params.id}`); return response.json();});export default component$(() => { const product = useProductData(); return <div>{product.value.name}</div>;});export const head = useDocumentHead$(({ resolveValue }) => { const product = resolveValue(useProductData); return { title: product.name, meta: [ { name: 'description', content: product.description }, { property: 'og:title', content: product.name }, { property: 'og:description', content: product.description }, { property: 'og:image', content: product.image } ] };});7. 国际化i18n 配置// src/entry.ssr.tsximport { renderToStream } from '@builder.io/qwik/server';import { Root } from './root';import { I18nProvider } from 'qwik-speak';export default function (opts) { return renderToStream(<Root />, { ...opts, containerAttributes: { lang: opts.lang } });}使用翻译import { component$ } from '@builder.io/qwik';import { useSpeak } from 'qwik-speak';export const MyComponent = component$(() => { const { t } = useSpeak(); return ( <div> <h1>{t('welcome.title')}</h1> <p>{t('welcome.description')}</p> </div> );});8. 最佳实践1. 合理使用 routeLoader$ 和 useResource$routeLoader$:用于页面级数据,在服务器执行useResource$:用于组件级数据,可以动态重新获取2. 错误处理export const useData = routeLoader$(async ({ params }) => { try { const response = await fetch(`https://api.example.com/data/${params.id}`); if (!response.ok) { throw new Error('Failed to fetch data'); } return response.json(); } catch (error) { throw requestEvent.redirect(302, '/error'); }});3. 缓存策略export const useCachedData = routeLoader$(async ({ requestEvent }) => { const cacheKey = 'data'; const cached = requestEvent.sharedMap.get(cacheKey); if (cached) { return cached; } const data = await fetchData(); requestEvent.sharedMap.set(cacheKey, data); return data;});总结:Qwik City 提供了完整的全栈开发体验,通过路由、数据加载、表单处理等功能,开发者可以快速构建高性能的 Web 应用程序。