# 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>

# 注意事项

  1. 组件依赖

    • 内部使用了 press-nextPressMatchTeamInfoItem 组件
    • 内部使用了 press-uiPressListPressEmpty 组件
    • 需要确保已正确安装相关依赖
  2. 数据加载

    • 组件本身不处理数据获取逻辑,需要通过 load-more 事件在父组件中实现数据加载
    • 建议对大量数据进行分页加载,避免一次性渲染过多内容
  3. 状态管理

    • loadingfinished 状态需要在父组件中正确管理
    • 加载开始时设置 loading: true,加载完成后设置 loading: false
    • 没有更多数据时设置 finished: true
  4. 标签优先级

    • 队伍数据中的 tagItems 会覆盖组件的 tag-items 属性
    • 如果队伍数据没有 tagItems,则使用组件的默认标签
  5. 显示模式

    • 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>

# 加载状态显示异常怎么办?

请检查 loadingfinished 状态的管理逻辑:

<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>