好的,让我们来实现文章搜索功能。我们将创建一个简单的搜索页面,允许用户通过标题、内容或作者名称搜索文章。

第十六部分:实现文章搜索功能

  1. 首先,在 src/routes 目录下创建一个新文件 search.ts
import { Elysia } from "elysia";
import { db } from "../db";
import { posts, users, categories, postCategories } from "../db/schema";
import { eq, like, or, and } from "drizzle-orm";
 
export const searchRoutes = new Elysia()
  .get("/search", async ({ query }) => {
    const { q } = query;
 
    if (!q) {
      return { posts: [], query: "" };
    }
 
    const searchResults = await db
      .select({
        id: posts.id,
        title: posts.title,
        content: posts.content,
        createdAt: posts.createdAt,
        author: users.username,
        categories: categories.name,
      })
      .from(posts)
      .leftJoin(users, eq(posts.authorId, users.id))
      .leftJoin(postCategories, eq(posts.id, postCategories.postId))
      .leftJoin(categories, eq(postCategories.categoryId, categories.id))
      .where(
        or(
          like(posts.title, `%${q}%`),
          like(posts.content, `%${q}%`),
          like(users.username, `%${q}%`)
        )
      )
      .all();
 
    // 对结果进行处理,合并相同文章的类别
    const processedResults = searchResults.reduce((acc, curr) => {
      const existingPost = acc.find(post => post.id === curr.id);
      if (existingPost) {
        if (curr.categories && !existingPost.categories.includes(curr.categories)) {
          existingPost.categories.push(curr.categories);
        }
      } else {
        acc.push({
          ...curr,
          categories: curr.categories ? [curr.categories] : []
        });
      }
      return acc;
    }, []);
 
    return { posts: processedResults, query: q };
  });
  1. src/index.ts 中导入并使用新的搜索路由:
import { searchRoutes } from "./routes/search";
 
// ... 其他导入保持不变
 
app.use(searchRoutes);
 
// ... 其他代码保持不变
  1. 创建一个新的视图文件 src/views/search.eta
<% layout('./layouts/main.eta', { title: 'Search Results' }) %>
 
<h1>Search Results</h1>
 
<form action="/search" method="GET">
  <input type="text" name="q" value="<%= it.query %>" placeholder="Search for posts...">
  <button type="submit">Search</button>
</form>
 
<% if (it.posts.length > 0) { %>
  <ul>
    <% it.posts.forEach(post => { %>
      <li>
        <h2><a href="/posts/<%= post.id %>"><%= post.title %></a></h2>
        <p>By <%= post.author %> on <%= new Date(post.createdAt).toLocaleDateString() %></p>
        <% if (post.categories && post.categories.length > 0) { %>
          <p>Categories: 
            <%= post.categories.join(', ') %>
          </p>
        <% } %>
        <p><%= post.content.substring(0, 200) %>...</p>
      </li>
    <% }) %>
  </ul>
<% } else if (it.query) { %>
  <p>No results found for "<%= it.query %>"</p>
<% } %>
  1. 更新 src/routes/search.ts 文件,添加渲染搜索结果页面的逻辑:
import { Elysia } from "elysia";
import { db } from "../db";
import { posts, users, categories, postCategories } from "../db/schema";
import { eq, like, or, and } from "drizzle-orm";
 
export const searchRoutes = new Elysia()
  .get("/search", async ({ query, render }) => {
    const { q } = query;
 
    if (!q) {
      return render("search", { posts: [], query: "" });
    }
 
    // ... 保持搜索逻辑不变
 
    return render("search", { posts: processedResults, query: q });
  });
  1. 在主布局文件 src/views/layouts/main.eta 中添加搜索表单:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><%= it.title %> - My Blog</title>
    <link rel="stylesheet" href="/styles/main.css">
</head>
<body>
    <header>
        <nav>
            <a href="/">Home</a>
            <a href="/posts/new">New Post</a>
            <% if (it.user) { %>
                <a href="/logout">Logout</a>
            <% } else { %>
                <a href="/login">Login</a>
                <a href="/register">Register</a>
            <% } %>
            <form action="/search" method="GET" class="search-form">
                <input type="text" name="q" placeholder="Search...">
                <button type="submit">Search</button>
            </form>
        </nav>
    </header>
    <main>
        <%~ it.body %>
    </main>
    <footer>
        <p>&copy; 2023 My Blog</p>
    </footer>
</body>
</html>
  1. 更新 public/styles/main.css 文件,添加一些搜索相关的样式:
/* ... 前面的样式保持不变 */
 
.search-form {
  display: inline-block;
  margin-left: 20px;
}
 
.search-form input[type="text"] {
  padding: 5px;
  width: 200px;
}
 
.search-form button {
  padding: 5px 10px;
  background-color: #007bff;
  color: white;
  border: none;
  cursor: pointer;
}
 
.search-results li {
  margin-bottom: 20px;
  border-bottom: 1px solid #ddd;
  padding-bottom: 10px;
}
 
.search-results h2 {
  margin-bottom: 5px;
}
 
.search-results p {
  margin: 5px 0;
}

这些更改实现了文章搜索功能:

  1. 创建了一个新的搜索路由,处理搜索请求。
  2. 实现了基于标题、内容和作者名称的搜索逻辑。
  3. 创建了一个新的搜索结果页面,显示搜索结果。
  4. 在主布局中添加了一个搜索表单,使搜索功能在所有页面都可用。
  5. 添加了相应的样式,使搜索功能看起来更加美观。

主要改进包括:

  • 用户可以通过标题、内容或作者名称搜索文章。
  • 搜索结果页面显示匹配的文章,包括标题、作者、发布日期、类别和内容预览。
  • 搜索表单在所有页面的顶部都可用,提高了可访问性。

这个搜索功能为用户提供了一种快速找到感兴趣内容的方法,提高了博客的可用性。

接下来,我们可以考虑添加以下功能:

  1. 用户头像上传
  2. 文章预览功能
  3. 标签云或热门标签功能
  4. 高级搜索选项(如按日期范围或特定类别搜索)

你希望继续哪个方向,或者有其他想法吗?