Vue 3 v-for 循环中实现按钮单选与切换激活状态教程

针对Vue 3中`v-for`循环渲染的按钮组,本文将详细介绍如何实现单选模式下的激活状态管理。通过Composition API和响应式数据,我们将学习如何确保每次只有一个按钮处于激活状态,并支持点击已激活按钮进行切换,使其变为非激活状态,从而提供灵活的用户交互体验。

引言

在现代前端应用中,列表筛选、标签选择等功能经常需要用户从一组选项中选择一个或不选择任何选项。Vue 3 结合 v-for 指令可以高效地渲染这类列表,但如何优雅地管理这些按钮的激活状态,特别是要实现“单选(同一时间只有一个激活)”和“切换(点击已激活按钮使其失效)”的复合逻辑,是开发者常遇到的挑战。本教程将深入探讨如何使用 Vue 3 的 Composition API 解决这一问题。

核心概念

要实现按钮的单选与切换功能,我们需要掌握以下几个核心概念:

  1. 响应式数据 (ref): Vue 3 的 Composition API 提供了 ref 来创建响应式引用。我们将使用一个 ref 来存储当前被选中的分类。
  2. v-for 循环: 用于遍历数组,动态渲染多个按钮。
  3. 动态类绑定 (:class): 根据响应式数据的状态,动态地为按钮添加或移除 CSS 类,以改变其视觉样式(如“激活”状态)。
  4. 事件处理 (@click): 监听按钮的点击事件,并在事件发生时执行相应的逻辑来更新响应式数据。

实现单选与切换逻辑

我们的目标是:

  • 点击一个未激活的按钮,使其变为激活状态,并取消其他所有按钮的激活状态。
  • 点击一个已激活的按钮,使其变为非激活状态。
  • 任何时候,最多只有一个按钮处于激活状态,也可以都没有激活。

1. 数据结构设计

为了实现上述逻辑,最简洁的方式是使用一个 ref 变量来存储当前激活的分类名称(或其唯一标识)。如果没有任何分类被激活,该变量可以为空字符串或 null。

// script setup 语法糖
import { ref } from 'vue';

// 定义分类列表
const contentCategories = ref(["Category 1", "Category 2", "Category 3", "Category 4"]);

// 定义当前选中的分类,初始为空字符串表示没有分类被选中
const selectedCategory = ref('');

2. 模板结构

在模板中,我们使用 v-for 遍历 contentCategories 数组,为每个分类渲染一个按钮。通过 :class 动态绑定一个 active 类,当按钮对应的分类与 selectedCategory.value 相同时,该按钮就拥有 active 类。

  • v-for="category in contentCategories": 遍历 contentCategories 数组。
  • :key="category": 在 v-for 中提供一个唯一的 key 是最佳实践,有助于 Vue 高效地更新 DOM。
  • @click="handleClick(category)": 当按钮被点击时,调用 handleClick 方法,并传入当前按钮对应的 category。
  • :class="{ 'filter-button': true, 'active': selectedCategory === category }":
    • filter-button: 这是一个基础样式类,所有按钮都拥有。
    • active: 这是一个条件类。当 selectedCategory.value 的值与当前循环中的 category 相等时,该类会被添加到按钮上。

3. 事件处理函数

handleClick 方法是实现核心逻辑的关键。它接收被点击的 category 作为参数,然后根据 selectedCategory.value 的当前状态来更新它:

// script setup 语法糖
import { ref } from 'vue';

const contentCategories = ref(["Category 1", "Category 2", "Category 3", "Category 4"]);
const selectedCategory = ref('');

const handleClick = (category) => {
  if (selectedCategory.value === category) {
    // 如果点击的分类已经是当前选中的分类,则将其取消选中
    selectedCategory.value = '';
  } else {
    // 否则,将当前点击的分类设为选中状态
    selectedCategory.value = category;
  }
};

代码解析:

  • 当用户点击一个按钮时,handleClick 函数会被调用,并传入该按钮的 category 值。
  • if (selectedCategory.value === category):判断当前点击的按钮是否已经是激活状态。
    • 如果是,说明用户想要取消选择。我们将 selectedCategory.value 设置为空字符串 '',表示没有任何分类被选中。
    • 如果不是,说明用户想要选择这个新的分类。我们将 selectedCategory.value 更新为当前点击的 category。由于 selectedCategory 是一个响应式引用,这个更新会自动触发模板的重新渲染,从而更新按钮的 active 类。

4. 完整示例代码

将上述代码片段整合到 Vue 3 的单文件组件(SFC)中,使用





拓展思考与注意事项

  1. 更复杂的分类数据: 如果你的分类不仅仅是字符串,而是包含 ID、名称、图标等属性的对象,你可以调整 contentCategories 的数据结构,并相应地修改 selectedCategory 存储的值(例如存储 ID)。

    // 示例:分类是对象数组
    const contentCategories = ref([
      { id: 'cat1', name: 'Category 1' },
      { id: 'cat2', name: 'Category 2' },
      // ...
    ]);
    const selectedCategoryId = ref(''); // 存储选中的分类ID
    
    const handleClick = (category) => {
      if (selectedCategoryId.value === category.id) {
        selectedCategoryId.value = '';
      } else {
        selectedCategoryId.value = category.id;
      }
    };

    模板中的 v-for 和 :class 也要相应调整:

  2. 与父组件通信: 如果这个按钮组是一个子组件,你可能需要将 selectedCategory 的变化通过 emit 事件传递给父组件。

    
    

    父组件可以这样使用:

  3. 可访问性: 对于生产环境应用,考虑为按钮添加 ARIA 属性,如 aria-pressed,以提升可访问性。

总结

通过 Vue 3 的 Composition API 和响应式数据,我们可以非常简洁高效地实现 v-for 循环中按钮的单选与切换激活状态。核心在于使用一个 ref 变量来追踪当前激活的状态,并通过动态 :class 绑定和事件处理函数来更新这个状态,从而驱动 UI 的变化。这种模式不仅适用于按钮组,也适用于任何需要管理单选或切换状态的列表渲染场景,是 Vue 3 开发中一个非常实用的技巧。