You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将按钮选中值添加到文章对象的category字段中?

文章分类选择功能实现问题及解决方案

问题背景

我正在搭建一个支持用户撰写文章的网站,用户提交表单就能保存文章。目前表单里的输入字段都能正常保存,但在做分类/标签系统时卡壳了。我想让用户能按分类(电视、电影、音乐等)筛选文章,这需要给文章加上分类属性。

当前代码情况

文章Schema

const ArticleSchema = new Schema({
  title: { type: String, required: true },
  content: { type: String, required: true },
  author: { type: String },
  createdAt: { type: Date, default: Date.now },
  category: {
    type: String,
    enum: ["Television", "Movie"],
  },
});

表单代码

<form action="" method="POST">
    <p class="main__article-p">Select Tags</p>
    <div class="main__article-category">
      <button class="main__article-button">Television</button>
      <button class="main__article-button">Movie</button>
      <button class="main__article-button">Music</button>
    </div>
      <div class="form-group">
        <label for="title">Write Your Title</label>
        <input
          name="title"
          required
        />
      </div>
      <div class="form-group">
        <label for="content">Write Your Content</label>
        <textarea
          name="content"
          required
        ></textarea>
      </div>
      <div class="form-group">
        <label for="author"></label>
        <input
          name="author"
          value="<%= author.username %>"
          hidden
        />
      </div>
      <button type="submit">Submit</button>
    </form>

POST请求处理代码

exports.article_create_post = [
  // Validate and sanitize fields.
  body("title", "Title must not be empty.")
    .trim()
    .isLength({ min: 1 })
    .escape(),
  body("content", "Content must not be empty.")
    .trim()
    .isLength({ min: 1 })
    .escape(),
  body("author").trim().escape(),
  body("category").trim().escape(),
  // Process request after validation and sanitization.
  (req, res, next) => {
    // Extract the validation errors from a request.
    const errors = validationResult(req);

    // Create a Book object with escaped and trimmed data.
    const article = new Article({
      title: req.body.title,
      content: req.body.content,
      author: req.body.author,
      category: req.body.category,
    });

    if (!errors.isEmpty()) {
      // There are errors. Render form again with sanitized values/error messages.

      // Get all authors and genres for form.
      async.parallel((err, results) => {
        if (err) {
          return next(err);
        }
        res.render("article_form", {
          title: "Create Article",
          author: author.username,
          content: content,
          category: category,
          article,
          errors: errors.array(),
        });
      });
      return;
    }

    // Data from form is valid. Save article.
    article.save((err) => {
      if (err) {
        return next(err);
      }
      // Successful: redirect to new article record.
      res.redirect(article.url);
    });
  },
];

核心问题

表单顶部的分类按钮,点击后无法将对应值传递给文章的category属性,不知道如何实现选择分类并提交的功能。

解决方案

1. 修正Schema的枚举值

当前Schema的category枚举只包含Television和Movie,但表单里有Music选项,必须更新枚举列表,否则保存Music分类会报错:

category: {
  type: String,
  enum: ["Television", "Movie", "Music"], // 添加Music
},

2. 两种表单分类选择实现方案

方案一:使用单选框(推荐,符合表单语义)

把原有的按钮改成单选框,再通过CSS样式模拟按钮外观,既保留表单原生的提交逻辑,又满足视觉需求。

修改表单的分类部分:

<div class="main__article-category">
  <label class="category-label">
    <input type="radio" name="category" value="Television" required>
    Television
  </label>
  <label class="category-label">
    <input type="radio" name="category" value="Movie" required>
    Movie
  </label>
  <label class="category-label">
    <input type="radio" name="category" value="Music" required>
    Music
  </label>
</div>

添加CSS样式模拟按钮:

/* 隐藏原生单选框 */
.category-label input[type="radio"] {
  display: none;
}

/* 标签样式模拟按钮 */
.category-label {
  display: inline-block;
  padding: 8px 16px;
  margin: 0 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
  cursor: pointer;
}

/* 选中状态样式 */
.category-label input[type="radio"]:checked + span {
  background-color: #007bff;
  color: white;
}

方案二:使用隐藏字段+JavaScript处理按钮点击

如果必须保留原有的按钮结构,通过隐藏字段存储分类值,用JS监听按钮点击事件赋值:

修改表单,添加隐藏字段并给按钮加类型和数据属性:

<form action="" method="POST">
    <p class="main__article-p">Select Tags</p>
    <!-- 添加隐藏字段存储分类值 -->
    <input type="hidden" name="category" id="categoryInput" required>
    <div class="main__article-category">
      <!-- 把按钮类型设为button,避免点击直接提交表单 -->
      <button type="button" class="main__article-button" data-category="Television">Television</button>
      <button type="button" class="main__article-button" data-category="Movie">Movie</button>
      <button type="button" class="main__article-button" data-category="Music">Music</button>
    </div>
    <!-- 其他表单字段不变 -->
</form>

添加JavaScript处理逻辑:

// 获取所有分类按钮和隐藏字段
const categoryButtons = document.querySelectorAll('.main__article-button');
const categoryInput = document.getElementById('categoryInput');

categoryButtons.forEach(button => {
  button.addEventListener('click', function() {
    // 移除所有按钮的选中样式
    categoryButtons.forEach(btn => btn.classList.remove('selected'));
    // 给当前点击的按钮添加选中样式
    this.classList.add('selected');
    // 将当前按钮的分类值赋值给隐藏字段
    categoryInput.value = this.dataset.category;
  });
});

添加选中状态的CSS样式:

.main__article-button.selected {
  background-color: #007bff;
  color: white;
  border-color: #007bff;
}

3. 完善表单验证

在POST处理的验证规则里,添加category的必填和枚举校验:

body("category", "Category is required.")
  .trim()
  .isIn(["Television", "Movie", "Music"])
  .escape(),

内容的提问来源于stack exchange,提问作者Dagger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 23:17:17