# MatchTeamInfoList 队伍信息列表
用于展示队伍信息的列表组件,支持滚动加载更多数据、空状态处理等功能。
# 引入
import PressMatchTeamInfoList from 'press-next/press-match-team-info-list/press-match-team-info-list.vue';
# 代码演示
# 基础用法
<template>
<PressMatchTeamInfoList
:team-list="teamList"
:loading="loading"
:finished="finished"
@load-more="loadMore"
@apply="handleApply"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import PressMatchTeamInfoList from 'press-next/press-match-team-info-list/press-match-team-info-list.vue';
const teamList = ref([]);
const loading = ref(false);
const finished = ref(false);
const currentPage = ref(0);
const pageSize = 10;
const loadMore = () => {
if (loading.value || finished.value) return;
loading.value = true;
// 模拟异步加载数据
setTimeout(() => {
const newData = generateTeamData(currentPage.value, pageSize);
if (newData.length > 0) {
teamList.value = [...teamList.value, ...newData];
currentPage.value += 1;
} else {
finished.value = true;
}
loading.value = false;
}, 1000);
};
const handleApply = (team, index) => {
console.log('申请加入队伍:', team, index);
};
// 生成模拟数据
const generateTeamData = (page, size) => {
const data = [];
const start = page * size;
const end = start + size;
for (let i = start; i < end && i < 50; i++) {
data.push({
id: `team-${i}`,
name: `战队${i + 1}`,
logo: `https://example.com/logo${i}.png`,
avatars: [
`https://example.com/avatar${i}-1.png`,
`https://example.com/avatar${i}-2.png`,
],
currentMembers: Math.floor(Math.random() * 5) + 1,
maxMembers: 5,
tagItems: [
{ text: '热门', type: 'primary' },
],
});
}
return data;
};
</script>
# 简单模式
不显示成员头像列表和操作按钮。
<template>
<PressMatchTeamInfoList
:team-list="teamList"
:loading="loading"
:finished="finished"
item-type="simple"
@load-more="loadMore"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import PressMatchTeamInfoList from 'press-next/press-match-team-info-list/press-match-team-info-list.vue';
const teamList = ref([
{
id: '1',
name: '王者荣耀战队',
logo: 'https://example.com/logo.png',
currentMembers: 3,
maxMembers: 5,
tagItems: [
{ text: '热门', type: 'primary' },
],
},
]);
const loading = ref(false);
const finished = ref(false);
const loadMore = () => {
console.log('加载更多');
};
</script>
# 自定义空状态
<template>
<PressMatchTeamInfoList
:team-list="teamList"
:loading="loading"
:finished="finished"
empty-text="暂无队伍信息"
finish-text="已加载全部队伍"
@load-more="loadMore"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import PressMatchTeamInfoList from 'press-next/press-match-team-info-list/press-match-team-info-list.vue';
const teamList = ref([]);
const loading = ref(false);
const finished = ref(false);
const loadMore = () => {
console.log('加载更多');
};
</script>
# 自定义标签
可以为每个队伍单独设置标签,也可以统一设置。
<template>
<PressMatchTeamInfoList
:team-list="teamList"
:tag-items="defaultTags"
:loading="loading"
:finished="finished"
@load-more="loadMore"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import PressMatchTeamInfoList from 'press-next/press-match-team-info-list/press-match-team-info-list.vue';
const defaultTags = ref([
{ text: '推荐', type: 'primary' },
]);
const teamList = ref([
{
id: '1',
name: '王者荣耀战队',
logo: 'https://example.com/logo.png',
avatars: ['https://example.com/avatar1.png'],
currentMembers: 3,
maxMembers: 5,
// 单独设置标签会覆盖默认标签
tagItems: [
{ text: '热门', type: 'primary' },
{ text: '3', type: 'quantity' },
],
},
{
id: '2',
name: '和平精英战队',
logo: 'https://example.com/logo2.png',
avatars: ['https://example.com/avatar2.png'],
currentMembers: 2,
maxMembers: 5,
// 不设置则使用默认标签
},
]);
const loading = ref(false);
const finished = ref(false);
const loadMore = () => {
console.log('加载更多');
};
</script>
# API
# Props
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| team-list | 队伍列表数据 | TeamInfo[] | [] |
| tag-items | 默认标签列表 | TagItem[] | [] |
| item-type | 列表项显示类型 | 'with-avatars' | 'simple' | 'with-avatars' |
| action-text | 操作按钮文字 | string | '申请加入' |
| custom-class | 自定义样式类名 | string | '' |
| empty-text | 空状态提示文字 | string | '暂无队伍信息' |
| image | 空状态图片 | string | - |
| finish-text | 加载完成提示文字 | string | '没有更多了' |
| loading | 是否正在加载 | boolean | false |
| finished | 是否已加载完成 | boolean | false |
# TeamInfo 数据结构
interface TeamInfo {
id: string;
name: string;
logo: string;
avatars?: string[];
currentMembers: number;
maxMembers: number;
tagItems?: TagItem[];
}
| 属性 | 说明 | 类型 | 必填 |
|---|---|---|---|
| id | 队伍 ID | string | 是 |
| name | 队伍名称 | string | 是 |
| logo | 队伍 logo | string | 是 |
| avatars | 成员头像列表 | string[] | 否 |
| currentMembers | 当前成员数 | number | 是 |
| maxMembers | 最大成员数 | number | 是 |
| tagItems | 队伍标签列表,会覆盖默认标签 | TagItem[] | 否 |
# TagItem 数据结构
interface TagItem {
text: string;
type?: 'default' | 'quantity';
}
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| text | 标签文本 | string | - |
| type | 标签类型,quantity 类型会显示用户图标 | 'default' | 'quantity' | 'default' |
# Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| load-more | 滚动到底部时触发 | - |
| apply | 点击申请加入按钮时触发 | team: TeamInfo, index: number |
# 主题定制
# CSS 变量
组件提供了下列 CSS 变量,可用于自定义样式。
# 间距系统
| 名称 | 默认值 | 描述 |
|---|---|---|
| --til-list-gap | 0 | 列表项间距 |
| --til-list-item-border-offset | $spacing-lg | 列表项边框偏移量 |
# 颜色系统
| 名称 | 默认值 | 描述 |
|---|---|---|
| --til-bg-color | transparent | 列表背景色 |
| --til-list-item-border-color | $color-divider-light | 列表项边框颜色 |
# 自定义样式示例
<template>
<PressMatchTeamInfoList
:team-list="teamList"
class="custom-team-list"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import PressMatchTeamInfoList from 'press-next/press-match-team-info-list/press-match-team-info-list.vue';
const teamList = ref([
{
id: '1',
name: '王者荣耀战队',
logo: 'https://example.com/logo.png',
avatars: ['https://example.com/avatar1.png'],
currentMembers: 3,
maxMembers: 5,
},
]);
</script>
<style scoped lang="scss">
.custom-team-list {
--til-bg-color: #f5f5f5;
--til-list-gap: 16px;
--til-list-item-border-color: #e0e0e0;
}
</style>
# 注意事项
组件依赖:
- 内部使用了
press-next的PressMatchTeamInfoItem组件 - 内部使用了
press-ui的PressList和PressEmpty组件 - 需要确保已正确安装相关依赖
- 内部使用了
数据加载:
- 组件本身不处理数据获取逻辑,需要通过
load-more事件在父组件中实现数据加载 - 建议对大量数据进行分页加载,避免一次性渲染过多内容
- 组件本身不处理数据获取逻辑,需要通过
状态管理:
loading和finished状态需要在父组件中正确管理- 加载开始时设置
loading: true,加载完成后设置loading: false - 没有更多数据时设置
finished: true
标签优先级:
- 队伍数据中的
tagItems会覆盖组件的tag-items属性 - 如果队伍数据没有
tagItems,则使用组件的默认标签
- 队伍数据中的
显示模式:
with-avatars模式:显示成员头像列表和操作按钮simple模式:不显示头像列表和操作按钮
# 常见问题
# 如何实现下拉刷新?
可以结合 press-ui 的下拉刷新组件使用:
<template>
<PressPullRefresh
v-model="refreshing"
@refresh="onRefresh"
>
<PressMatchTeamInfoList
:team-list="teamList"
:loading="loading"
:finished="finished"
@load-more="loadMore"
/>
</PressPullRefresh>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import PressMatchTeamInfoList from 'press-next/press-match-team-info-list/press-match-team-info-list.vue';
import PressPullRefresh from 'press-ui/press-pull-refresh/press-pull-refresh.vue';
const teamList = ref([]);
const loading = ref(false);
const finished = ref(false);
const refreshing = ref(false);
const onRefresh = async () => {
// 重置状态
teamList.value = [];
finished.value = false;
// 重新加载数据
await loadMore();
refreshing.value = false;
};
const loadMore = async () => {
loading.value = true;
// 加载数据逻辑
loading.value = false;
};
</script>
# 如何自定义队伍项的样式?
组件内部使用 PressMatchTeamInfoItem 组件渲染每个队伍项,可以通过 CSS 变量进行定制:
<template>
<PressMatchTeamInfoList
:team-list="teamList"
class="custom-list"
/>
</template>
<style scoped lang="scss">
.custom-list {
// 自定义列表样式
--til-list-gap: 16px;
// 自定义队伍项样式
--pmtii-container-bg: #f5f5f5;
--pmtii-name-text-color: #1890ff;
}
</style>
# 加载状态显示异常怎么办?
请检查 loading 和 finished 状态的管理逻辑:
<script setup lang="ts">
const loading = ref(false);
const finished = ref(false);
const loadMore = async () => {
// 防止重复加载
if (loading.value || finished.value) return;
loading.value = true;
try {
const newData = await fetchTeamData();
if (newData.length > 0) {
teamList.value = [...teamList.value, ...newData];
} else {
// 没有更多数据
finished.value = true;
}
} catch (error) {
console.error('加载失败:', error);
} finally {
// 确保加载状态被重置
loading.value = false;
}
};
</script>
# 如何处理申请加入逻辑?
监听 apply 事件,在回调中处理申请逻辑:
<template>
<PressMatchTeamInfoList
:team-list="teamList"
@apply="handleApply"
/>
</template>
<script setup lang="ts">
const handleApply = async (team, index) => {
try {
// 调用申请接口
await applyToJoinTeam(team.id);
console.log('申请成功');
// 更新列表状态
teamList.value[index].isApplied = true;
} catch (error) {
console.error('申请失败:', error);
}
};
</script>