Preact Router基础 #
一、路由概述 #
1.1 什么是路由 #
路由允许根据 URL 显示不同的组件,实现单页应用(SPA)的页面切换。
text
URL 组件
/home → HomePage
/about → AboutPage
/users/:id → UserDetail
1.2 安装 #
bash
npm install preact-router
1.3 基本结构 #
jsx
import { Router } from 'preact-router';
import { HomePage, AboutPage, ContactPage } from './pages';
function App() {
return (
<Router>
<HomePage path="/" />
<AboutPage path="/about" />
<ContactPage path="/contact" />
</Router>
);
}
二、基本路由 #
2.1 定义路由 #
jsx
import { Router } from 'preact-router';
function App() {
return (
<Router>
<Home path="/" />
<About path="/about" />
<Contact path="/contact" />
<NotFound default />
</Router>
);
}
function Home() {
return <h1>Home Page</h1>;
}
function About() {
return <h1>About Page</h1>;
}
function Contact() {
return <h1>Contact Page</h1>;
}
function NotFound() {
return <h1>404 - Page Not Found</h1>;
}
2.2 默认路由 #
jsx
<Router>
<Home path="/" />
<About path="/about" />
<NotFound default /> {/* 匹配所有未定义的路由 */}
</Router>
2.3 布局路由 #
jsx
function App() {
return (
<Router>
<Layout path="/">
<Home path="/" />
<About path="/about" />
</Layout>
<AdminLayout path="/admin">
<Dashboard path="/" />
<Users path="/users" />
</AdminLayout>
</Router>
);
}
function Layout({ children }) {
return (
<div class="layout">
<Header />
<main>{children}</main>
<Footer />
</div>
);
}
三、导航 #
3.1 Link 组件 #
jsx
import { Link } from 'preact-router/match';
function Navigation() {
return (
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/contact">Contact</Link>
</nav>
);
}
3.2 激活状态 #
jsx
import { Link } from 'preact-router/match';
function Navigation() {
return (
<nav>
{/* activeClassName 自动添加激活类 */}
<Link href="/" activeClassName="active">Home</Link>
<Link href="/about" activeClassName="active">About</Link>
<Link href="/contact" activeClassName="active">Contact</Link>
</nav>
);
}
3.3 编程式导航 #
jsx
import { route } from 'preact-router';
function LoginForm() {
const handleSubmit = async (e) => {
e.preventDefault();
const success = await login(credentials);
if (success) {
route('/dashboard'); // 编程式导航
}
};
return (
<form onSubmit={handleSubmit}>
{/* ... */}
</form>
);
}
3.4 返回上一页 #
jsx
import { route } from 'preact-router';
function BackButton() {
const handleBack = () => {
if (window.history.length > 1) {
window.history.back();
} else {
route('/');
}
};
return <button onClick={handleBack}>Go Back</button>;
}
四、路由参数 #
4.1 动态参数 #
jsx
function App() {
return (
<Router>
<UserList path="/users" />
<UserDetail path="/users/:id" />
</Router>
);
}
function UserDetail({ id }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(id).then(setUser);
}, [id]);
if (!user) return <p>Loading...</p>;
return (
<div>
<h1>{user.name}</h1>
<p>Email: {user.email}</p>
</div>
);
}
4.2 多个参数 #
jsx
function App() {
return (
<Router>
<Post path="/posts/:category/:id" />
</Router>
);
}
function Post({ category, id }) {
return (
<div>
<h1>Category: {category}</h1>
<p>Post ID: {id}</p>
</div>
);
}
4.3 可选参数 #
jsx
function App() {
return (
<Router>
<Search path="/search/:query?" />
</Router>
);
}
function Search({ query }) {
return (
<div>
<h1>Search Results</h1>
<p>Query: {query || 'All results'}</p>
</div>
);
}
4.4 查询参数 #
jsx
import { useEffect, useState } from 'preact/hooks';
function SearchPage() {
const [query, setQuery] = useState('');
useEffect(() => {
const params = new URLSearchParams(window.location.search);
setQuery(params.get('q') || '');
}, []);
return (
<div>
<h1>Search: {query}</h1>
</div>
);
}
// 使用
// /search?q=preact
五、嵌套路由 #
5.1 基本嵌套 #
jsx
function App() {
return (
<Router>
<Dashboard path="/dashboard">
<Overview path="/" />
<Analytics path="/analytics" />
<Settings path="/settings" />
</Dashboard>
</Router>
);
}
function Dashboard({ children }) {
return (
<div class="dashboard">
<Sidebar />
<div class="content">
{children}
</div>
</div>
);
}
function Overview() {
return <h1>Overview</h1>;
}
function Analytics() {
return <h1>Analytics</h1>;
}
function Settings() {
return <h1>Settings</h1>;
}
5.2 带参数的嵌套路由 #
jsx
function App() {
return (
<Router>
<UserLayout path="/users/:userId">
<UserProfile path="/" />
<UserPosts path="/posts" />
<UserSettings path="/settings" />
</UserLayout>
</Router>
);
}
function UserLayout({ userId, children }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]);
if (!user) return <p>Loading...</p>;
return (
<div class="user-layout">
<UserHeader user={user} />
<nav>
<Link href={`/users/${userId}`}>Profile</Link>
<Link href={`/users/${userId}/posts`}>Posts</Link>
<Link href={`/users/${userId}/settings`}>Settings</Link>
</nav>
<div class="user-content">
{children}
</div>
</div>
);
}
六、路由事件 #
6.1 监听路由变化 #
jsx
import { useEffect } from 'preact/hooks';
import { getCurrentUrl, subscribe } from 'preact-router';
function App() {
useEffect(() => {
const unsubscribe = subscribe((url) => {
console.log('Route changed to:', url);
});
return unsubscribe;
}, []);
return (
<Router>
{/* ... */}
</Router>
);
}
6.2 获取当前 URL #
jsx
import { getCurrentUrl } from 'preact-router';
function CurrentPath() {
const [currentPath, setCurrentPath] = useState(getCurrentUrl());
useEffect(() => {
const unsubscribe = subscribe((url) => {
setCurrentPath(url);
});
return unsubscribe;
}, []);
return <p>Current path: {currentPath}</p>;
}
七、路由守卫 #
7.1 认证保护 #
jsx
import { route } from 'preact-router';
import { useContext, useEffect } from 'preact/hooks';
function ProtectedRoute({ component: Component, ...props }) {
const { user } = useContext(AuthContext);
useEffect(() => {
if (!user) {
route('/login', true); // true 表示替换历史记录
}
}, [user]);
if (!user) {
return null;
}
return <Component {...props} />;
}
// 使用
function App() {
return (
<Router>
<Home path="/" />
<Login path="/login" />
<ProtectedRoute path="/dashboard" component={Dashboard} />
<ProtectedRoute path="/settings" component={Settings} />
</Router>
);
}
7.2 权限检查 #
jsx
function AuthorizedRoute({ component: Component, permission, ...props }) {
const { user } = useContext(AuthContext);
useEffect(() => {
if (!user || !user.permissions.includes(permission)) {
route('/unauthorized', true);
}
}, [user, permission]);
if (!user || !user.permissions.includes(permission)) {
return null;
}
return <Component {...props} />;
}
八、404 处理 #
8.1 默认 404 页面 #
jsx
function App() {
return (
<Router>
<Home path="/" />
<About path="/about" />
<NotFound default />
</Router>
);
}
function NotFound() {
return (
<div class="not-found">
<h1>404</h1>
<p>Page not found</p>
<Link href="/">Go Home</Link>
</div>
);
}
九、最佳实践 #
9.1 路由配置 #
jsx
// routes.js
export const routes = {
home: '/',
about: '/about',
contact: '/contact',
user: (id) => `/users/${id}`,
userPosts: (id) => `/users/${id}/posts`
};
// 使用
import { routes } from './routes';
<Link href={routes.home}>Home</Link>
<Link href={routes.user(userId)}>User Profile</Link>
9.2 懒加载路由 #
jsx
import { lazy, Suspense } from 'preact/compat';
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Settings = lazy(() => import('./pages/Settings'));
function App() {
return (
<Router>
<Home path="/" />
<Suspense fallback={<div>Loading...</div>}>
<Dashboard path="/dashboard" />
<Settings path="/settings" />
</Suspense>
</Router>
);
}
十、总结 #
| 要点 | 说明 |
|---|---|
| Router | 路由容器 |
| path | 定义路由路径 |
| Link | 导航链接 |
| route | 编程式导航 |
| 参数 | :id 动态参数 |
核心原则:
- 使用 Link 进行导航
- 合理组织路由结构
- 实现路由守卫保护
- 处理 404 情况
最后更新:2026-03-28