對于使用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. 定義「需要篩選的目標數據」(示例:模型列表,實際可能從接口獲?。?/p>
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` 里的過濾邏輯。

浙公網安備 33010602011771號