好的, 让我们通过一个复杂的示例来展示在 Bun 环境下, 使用 Elysia 作为后端和 HTMX 作为前端时如何传递参数。这个示例将包含一个用户管理系统, 涉及用户列表、添加用户和编辑用户的功能。
首先, 我们来设置 Elysia 后端:
import { Elysia, t } from 'elysia'
import { html } from '@elysiajs/html'
const app = new Elysia()
.use(html())
// 用户类型定义
type User = {
id: number
name: string
email: string
role: 'admin' | 'user'
}
// 模拟数据库
let users: User[] = [
{ id: 1, name: 'John Doe', email: 'john@example.com', role: 'admin' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'user' },
]
// 主页路由
app.get('/', () => `
<html>
<head>
<script src="https://unpkg.com/htmx.org@1.9.6"></script>
</head>
<body>
<h1>User Management System</h1>
<div id="user-list" hx-get="/users" hx-trigger="load">Loading users...</div>
<button hx-get="/users/new" hx-target="#user-form">Add New User</button>
<div id="user-form"></div>
</body>
</html>
`)
// 获取用户列表
app.get('/users', () => {
return `
<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Role</th>
<th>Actions</th>
</tr>
${users.map(user => `
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.email}</td>
<td>${user.role}</td>
<td>
<button hx-get="/users/${user.id}/edit" hx-target="#user-form">Edit</button>
<button hx-delete="/users/${user.id}" hx-target="closest tr" hx-confirm="Are you sure?">Delete</button>
</td>
</tr>
`).join('')}
</table>
`
})
// 新用户表单
app.get('/users/new', () => `
<form hx-post="/users" hx-target="#user-list" hx-swap="outerHTML">
<input type="text" name="name" placeholder="Name" required>
<input type="email" name="email" placeholder="Email" required>
<select name="role" required>
<option value="user">User</option>
<option value="admin">Admin</option>
</select>
<button type="submit">Add User</button>
</form>
`)
// 添加新用户
app.post('/users', ({ body }) => {
const newUser: User = {
id: users.length + 1,
name: body.name,
email: body.email,
role: body.role as 'admin' | 'user'
}
users.push(newUser)
return app.handlers.get['/users']()
}, {
body: t.Object({
name: t.String(),
email: t.String(),
role: t.Union([t.Literal('admin'), t.Literal('user')])
})
})
// 编辑用户表单
app.get('/users/:id/edit', ({ params }) => {
const user = users.find(u => u.id === parseInt(params.id))
if (!user) return 'User not found'
return `
<form hx-put="/users/${user.id}" hx-target="#user-list" hx-swap="outerHTML">
<input type="text" name="name" value="${user.name}" required>
<input type="email" name="email" value="${user.email}" required>
<select name="role" required>
<option value="user" ${user.role === 'user' ? 'selected' : ''}>User</option>
<option value="admin" ${user.role === 'admin' ? 'selected' : ''}>Admin</option>
</select>
<button type="submit">Update User</button>
</form>
`
})
// 更新用户
app.put('/users/:id', ({ params, body }) => {
const index = users.findIndex(u => u.id === parseInt(params.id))
if (index === -1) return 'User not found'
users[index] = { ...users[index], ...body }
return app.handlers.get['/users']()
}, {
body: t.Object({
name: t.String(),
email: t.String(),
role: t.Union([t.Literal('admin'), t.Literal('user')])
})
})
// 删除用户
app.delete('/users/:id', ({ params }) => {
users = users.filter(u => u.id !== parseInt(params.id))
return ''
})
app.listen(3000)这个例子展示了 Elysia 和 HTMX 之间的几种参数传递方式:
-
URL 参数: 在编辑和删除用户时, 我们通过 URL 传递用户 ID。例如:
/users/:id/edit和/users/:id。 -
表单数据: 在添加和更新用户时, 我们使用表单提交数据。HTMX 会自动将表单数据序列化并发送到服务器。
-
HTMX 属性: 我们使用多种 HTMX 属性来控制行为, 如
hx-get,hx-post,hx-put,hx-delete,hx-target,hx-swap等。 -
查询参数: 虽然这个例子中没有使用, 但你也可以通过 URL 查询参数传递数据, 例如:
/users?page=1&limit=10。 -
自定义请求头: HTMX 允许你设置自定义请求头, 可以用来传递额外的元数据。
-
JSON 数据: 对于更复杂的数据结构, 你可以使用 JSON 格式通过请求体发送数据。
在这个例子中:
- 主页 (
/)加载时, HTMX 自动发起请求获取用户列表。 - 点击”Add New User”按钮会加载新用户表单。
- 提交新用户表单时, 数据通过 POST 请求发送到服务器。
- 编辑用户时, 先加载带有用户当前数据的表单, 然后通过 PUT 请求更新数据。
- 删除用户通过 DELETE 请求实现。
这个示例展示了如何使用 Elysia 和 HTMX 创建一个动态的、无需页面刷新的用户管理系统。它利用了 HTMX 的声明式属性来处理 AJAX 请求, 而 Elysia 则负责处理这些请求并返回适当的 HTML 片段。