对于使用ant design组件库的疑问

用ant design 的tag来制作组件封装然后实现应该筛选功能的话,我得考虑什么,具体筛选是点击tag之后会得到对应的筛选后的信息,我的后端接口应该是放在主页面没问题,然后传类别和该类别的tag,但是tag是能选择了,那数据还是没筛选啊,听前辈说是ant design的组件有个回调函数,但是我不会用,而且这个ant design的tag组件还有自带的api之类的东西,但是我不会用,首先我该怎么实现筛选的逻辑,回调函数是干什么的,然后我怎么用自带的api。

(最好不要在不了解一段代码的前提下,修改或增加代码的逻辑)

 

要使用 Ant Design Design 的 Tag 组件实现筛选功能,核心是通过 **状态管理** + **Tag 交互回调** + **数据过滤/接口请求** 来完成。下面分步骤拆解逻辑、回调函数的作用及 API 使用方法:

### 一、筛选功能的核心逻辑

筛选的本质是:**用户点击 Tag 后,记录选中的筛选条件,然后根据条件过滤数据(或重新请求接口)**。 

具体流程:

1. **维护选中状态**:用一个变量(如数组)存储用户当前选中的 Tag 值(例如 `selectedTags: ['电影', '音乐']`)。

2. **Tag 交互触发状态变更**:用户点击 Tag 时,通过回调函数更新选中状态(添加/移除 Tag 值)。

3. **根据状态筛选数据**:

   - 若数据在前端(已获取全量数据):用 `filter` 方法根据 `selectedTags` 过滤数据。

   - 若数据需要后端筛选:将 `selectedTags` 作为参数传给后端接口,重新请求数据。

 

 

### 二、Tag 组件的回调函数作用

Ant Design 的 Tag 组件(尤其是 `CheckableTag`,即“可选择标签”)的回调函数是 **用户交互与状态更新的桥梁**,核心回调如下:

 

| 组件         | 回调函数       | 作用                                                                 |

|--------------|----------------|----------------------------------------------------------------------|

| `Tag`        | `onClose`      | 当 Tag 可关闭时(设置了 `closeIcon`),点击关闭按钮触发,用于移除标签。 |

| `CheckableTag`| `onChange`     | 点击 Tag 时触发(切换选中状态),返回当前是否选中(`checked: boolean`),用于更新选中状态。 |

 

**为什么用 `CheckableTag` 而不是普通 `Tag`?** 

普通 `Tag` 更适合“展示/删除标签”,而 `CheckableTag` 自带“选中/未选中”状态切换(类似复选框),更适合筛选场景(支持多选)。

 

 

### 四、Ant Design Tag 常用 API 说明

#### 1. 基础 `Tag` 组件(用于展示/关闭标签,较少用于筛选)

| 参数        | 说明                          | 示例                                  |

|-------------|-------------------------------|---------------------------------------|

| `color`     | 标签颜色(预设值或色值)      | `<Tag color="success">成功</Tag>`     |

| `closeIcon` | 自定义关闭按钮(开启可关闭)  | `<Tag closeIcon={<CloseOutlined />} onClose={handleClose}>` |

| `onClose`   | 关闭标签时的回调              | `(e) => { console.log('关闭标签'); }` |

 

#### 2. `CheckableTag` 组件(筛选核心,支持选中状态)

| 参数       | 说明                          | 示例                                      |

|------------|-------------------------------|-------------------------------------------|

| `checked`  | 是否选中(受控属性)          | `checked={selectedTags.includes(tag)}`    |

| `onChange` | 点击切换选中状态的回调        | `(checked) => handleTagChange(tag, checked)` |

| `icon`     | 标签前的图标(>=5.27.0 支持) | `<CheckableTag icon={<MusicOutlined />}>音乐</CheckableTag>` |

 

 

 

### 总结

1. **筛选逻辑**:通过 `selectedTags` 记录选中条件,状态变化时触发数据过滤/接口请求。

2. **回调函数**:`CheckableTag` 的 `onChange` 是核心,用于更新选中状态;`Tag` 的 `onClose` 用于移除标签(适合“已选标签列表”场景)。

3. **API 用法**:`CheckableTag` 需通过 `checked` 绑定状态,`onChange` 处理交互;可结合 `icon` 等属性增强视觉效果。

 

 

 

 

 

 

这是我的代码,能点击但是没实现筛选功能,是不是少了什么。父组件

<template>

  <div class="p-6 bg-gray-100 items-start justify-start">

    <Tag :tags="parentObject"></Tag>

  </div>

</template>

 

<script lang="ts" setup>

import { ref, reactive, onMounted } from 'vue';

import Tag from '@/components/Tag/Tag.vue';

const parentObject = reactive([

  {

    label: '模型类型',

    tagsData: [

      '全部',

      '文本生成',

      '推理模型',

      '音频理解',

      '视频理解',

      '图片处理',

      '图片理解',

      '图片生成',

      '向量模型',

      '视频生成',

      '全模态',

      '语音合成',

      '语音识别',

      '排序模型'

    ],

    selectTags: [true, true, true, false, false, false, false, false, false, false, false, false, false, false]

  },

  {

    label: '上下文长度',

    tagsData: ['全部', '16K以下', '16K-64K', '64K以上'],

    selectTags: [true, true, true, false]

  }

]);

 

 

子组件

<template>

  <div v-for="group in tags" :key="group.label" class="pb-2 space-y-4">

    <span style="margin-right: 40px">{{ group.label }}</span>

    <a-space :size="[0, 8]" wrap>

      <a-checkable-tag

        v-for="(tag, index) in group.tagsData"

        :key="tag"

        v-model:checked="group.selectTags[index]"

        @change="(checked) => handleChange(tag, checked)"

      >

        {{ tag }}

      </a-checkable-tag>

    </a-space>

  </div>

  <div class="pb-5"></div>

</template>

 

<script setup>

import { reactive } from 'vue';

// const tagsData = reactive(['Movies', 'Books', 'Music', 'Sports']);

// const selectTags = reactive([true, false, false, false]);

const handleChange = (tag, checked) => {

  console.log(tag, checked);

};

 

defineOptions({ name: 'Tag' });

const props = defineProps({

  tags: {

    type: Array,

    required: true

  }

});

</script>

 

代码已经实现了「Tag 选中状态切换」,但没实现筛选功能,核心缺失两点:**1. 筛选条件的跨组件传递(子组件→父组件);2. 父组件根据筛选条件过滤数据**。下面分步骤补全逻辑:

### 一、先明确筛选功能的核心流程

1. 子组件(Tag):用户点击 Tag 时,收集当前「所有分组的选中标签」(比如“模型类型”选了哪些、“上下文长度”选了哪些)。 

2. 父子通信:子组件将收集到的「筛选条件」传给父组件(通过 Vue 的 `emit` 事件)。 

3. 父组件:接收筛选条件,用条件过滤目标数据(比如过滤“模型列表”),并渲染筛选结果。

 

 

### 二、第一步:子组件补全「收集筛选条件 + 向父组件传值」

子组件当前只打印了 `tag` 和 `checked`,但没有记录「每个分组最终选中的标签」,也没把结果传给父组件。需要:

1. 监听 `group.selectTags` 的变化(因为 `v-model:checked` 绑定的是这个数组,选中状态变了它会更新)。 

2. 实时收集每个分组的「选中标签」,并通过 `emit` 传给父组件。

 

#### 子组件(Tag.vue)修改代码:

```vue

<template>

  <div v-for="group in tags" :key="group.label" class="pb-2 space-y-4">

    <span style="margin-right: 40px">{{ group.label }}</span>

    <a-space :size="[0, 8]" wrap>

      <a-checkable-tag

        v-for="(tag, index) in group.tagsData"

        :key="tag"

        v-model:checked="group.selectTags[index]"

        @change="(checked) => handleChange(group, tag, index, checked)"

      >

        {{ tag }}

      </a-checkable-tag>

    </a-space>

  </div>

  <div class="pb-5"></div>

</template>

 

<script setup>

import { watch, onMounted } from 'vue';

 

// 1. 定义向父组件传递筛选条件的事件

const emit = defineEmits(['update:filterParams']);

 

// 2. 处理 Tag 变化:实时收集所有分组的选中标签

const collectFilterParams = (tags) => {

  // 最终要传给父组件的筛选条件格式(示例):

  // { "模型类型": ["全部", "文本生成"], "上下文长度": ["全部"] }

  const filterParams = {};

 

  tags.forEach(group => {

    // 遍历每个分组,找到 selectTags 为 true 的标签

    const selectedTags = group.tagsData.filter(

      (_, index) => group.selectTags[index] === true

    );

    // 给筛选条件赋值(键:分组label,值:选中的标签数组)

    filterParams[group.label] = selectedTags;

  });

 

  // 3. 把筛选条件传给父组件

  emit('update:filterParams', filterParams);

};

 

// 4. Tag 点击时触发(可选:也可以用 watch 监听 selectTags 变化)

const handleChange = (group, tag, index, checked) => {

  console.log(`分组:${group.label},标签:${tag},是否选中:${checked}`);

  // 每次点击后,重新收集筛选条件并传值

  collectFilterParams(props.tags);

};

 

// 5. 初始化时也收集一次(避免页面加载时没筛选条件)

onMounted(() => {

  collectFilterParams(props.tags);

});

 

// 6. 监听 selectTags 变化(防止手动修改数组时没触发传值,可选但建议加)

watch(

  () => props.tags,

  (newTags) => {

    collectFilterParams(newTags);

  },

  { deep: true } // 深度监听数组内部元素变化

);

 

// 接收父组件传来的 tags  props

defineOptions({ name: 'Tag' });

const props = defineProps({

  tags: {

    type: Array,

    required: true,

    // 确保 props 格式正确(每个分组必须有 label/tagsData/selectTags)

    validator: (value) => {

      return value.every(group =>

        group.label && Array.isArray(group.tagsData) && Array.isArray(group.selectTags)

      );

    }

  }

});

</script>

```

 

 

### 三、第二步:父组件补全「接收筛选条件 + 过滤数据」

父组件当前只传了 `parentObject` 给子组件,但没有:

1. 接收子组件传来的筛选条件; 

2. 定义「需要筛选的目标数据」(比如“模型列表”); 

3. 根据筛选条件过滤数据并渲染。

 

#### 父组件修改代码:

```vue

<template>

  <div class="p-6 bg-gray-100 items-start justify-start">

    <!-- 1. 子组件:通过 @update:filterParams 接收筛选条件 -->

    <Tag

      :tags="parentObject"

      @update:filterParams="handleFilterParamsChange"

    />

 

    <!-- 3. 渲染筛选后的结果 -->

    <div class="mt-6">

      <h3>筛选结果(共 {{ filteredModelList.length }} 条)</h3>

      <div class="mt-2 bg-white p-4 rounded-md">

        <div v-if="filteredModelList.length === 0">暂无匹配数据</div>

        <div v-else v-for="model in filteredModelList" :key="model.id" class="py-2 border-b">

          {{ model.name }}(模型类型:{{ model.type }},上下文长度:{{ model.contextLength }})

        </div>

      </div>

    </div>

  </div>

</template>

 

<script lang="ts" setup>

import { ref, reactive } from 'vue';

import Tag from '@/components/Tag/Tag.vue';

 

// 2. 定义「需要筛选的目标数据」(示例:模型列表,实际可能从接口获取)

const modelList = reactive([

  { id: 1, name: 'GPT-4', type: '文本生成', contextLength: '16K以下' },

  { id: 2, name: 'Stable Diffusion', type: '图片生成', contextLength: '16K-64K' },

  { id: 3, name: 'Whisper', type: '语音识别', contextLength: '64K以上' },

  { id: 4, name: 'CLIP', type: '图片理解', contextLength: '16K以下' },

  { id: 5, name: 'Gemini Pro', type: '全模态', contextLength: '16K-64K' },

]);

 

// 3. 存储筛选后的结果(初始为全部数据)

const filteredModelList = ref([...modelList]);

 

// 4. 接收子组件传来的筛选条件,并执行筛选

const handleFilterParamsChange = (filterParams) => {

  console.log('父组件接收的筛选条件:', filterParams);

  // filterParams 格式:{ "模型类型": ["全部", "文本生成"], "上下文长度": ["全部"] }

 

  // 执行筛选逻辑

  filteredModelList.value = modelList.filter(model => {

    // 条件1:模型类型匹配(若选中“全部”,则直接满足;否则匹配选中的类型)

    const typeCondition = filterParams['模型类型'].includes('全部')

      ? true

      : filterParams['模型类型'].includes(model.type);

 

    // 条件2:上下文长度匹配(同理)

    const contextCondition = filterParams['上下文长度'].includes('全部')

      ? true

      : filterParams['上下文长度'].includes(model.contextLength);

 

    // 两个条件都满足才保留

    return typeCondition && contextCondition;

  });

};

 

// 父组件传给子组件的 Tag 分组数据(保持不变)

const parentObject = reactive([

  {

    label: '模型类型',

    tagsData: [

      '全部', '文本生成', '推理模型', '音频理解', '视频理解',

      '图片处理', '图片理解', '图片生成', '向量模型', '视频生成',

      '全模态', '语音合成', '语音识别', '排序模型'

    ],

    selectTags: [true, true, true, false, false, false, false, false, false, false, false, false, false, false]

  },

  {

    label: '上下文长度',

    tagsData: ['全部', '16K以下', '16K-64K', '64K以上'],

    selectTags: [true, true, true, false]

  }

]);

</script>

```

 

 

### 四、关键问题解释:为什么之前没实现筛选?

1. **缺失「筛选条件的传递」**: 

   子组件只改了 `group.selectTags` 的状态,但没把“哪些标签被选中”告诉父组件——父组件不知道用户选了什么,自然无法筛选。 

   补全:通过 `emit` 事件,子组件把收集到的 `filterParams` 传给父组件。

 

2. **缺失「目标数据和过滤逻辑」**: 

   筛选需要「原始数据」(比如 `modelList`)和「过滤规则」(比如“模型类型匹配且上下文长度匹配”),之前父组件没有这两部分,所以没地方执行筛选。 

   补全:定义 `modelList` 作为原始数据,在 `handleFilterParamsChange` 中写过滤逻辑,更新 `filteredModelList` 并渲染。

 

 

### 五、优化建议(可选)

1. 处理「全部」标签的逻辑: 

   目前如果选中“全部”,会忽略其他选中的标签(因为 `includes('全部')` 直接返回 `true`),可以优化为:**若选中“全部”,则该分组只保留“全部”,取消其他标签的选中状态**(避免“全部”和其他标签同时选中的矛盾)。

 

2. 从接口获取数据: 

   如果数据量较大,父组件的 `modelList` 可以从后端接口获取,筛选时也可以把 `filterParams` 传给接口(后端筛选),而不是前端过滤。

 

3. 初始筛选: 

   页面加载时,`onMounted` 会触发一次筛选,确保初始状态也能展示正确的结果。

 

 

这样修改后,点击 Tag 就能实时筛选并展示数据了,你可以根据实际的“目标数据结构”调整 `handleFilterParamsChange` 里的过滤逻辑。

posted @ 2025-10-13 00:13  BKYNEKO  阅读(16)  评论(0)    收藏  举报