LiveListState 是 AtomicXCore 中负责管理直播房间列表、创建、加入以及维护房间状态的核心模块。通过LiveListState,您可以为您的应用构建完整的直播生命周期管理。
核心功能
直播列表拉取:获取当前所有公开的直播间列表,支持分页加载。
直播生命周期管理:提供从创建、开播、加入、离开到结束直播的全套流程接口。
直播信息更新:主播可以随时更新直播间的公开信息,例如封面、公告等。
实时事件监听:监听直播结束、用户被踢出等关键事件。
自定义业务数据:强大的自定义元数据(
MetaData)能力,允许您在房间内存储和同步任何业务相关的信息,例如直播状态、音乐信息、自定义角色等 。实现步骤
步骤1:组件集成
步骤2:实现观众从直播列表进入直播间
创建一个展示直播列表的页面。当用户点击某个卡片时,获取该直播间的
liveID,并跳转到观众观看页面。<template><view class="live-list"><!-- 直播列表 --><list class="list" :show-scrollbar="false"><!-- 行循环 --><cell v-for="(row, idx) in groupedList" :key="`row-${idx}`"><view class="row"><!-- 卡片循环 --><viewv-for="live in row":key="live.liveID"class="card"@tap="handleJoinLive(live)"><image :src="live.coverURL || defaultCover" class="cover" /><view class="info"><text class="title">{{ live.liveName }}</text><text class="owner">{{ live.liveOwner?.userName }}</text><text class="count">{{ live.totalViewerCount }}人看过</text></view></view></view></cell></list></view></template><script setup lang="ts">import { computed, onMounted } from 'vue';import { useLiveListState } from "@/uni_modules/tuikit-atomic-x/state/LiveListState";// 状态管理const { liveList, liveListCursor, fetchLiveList } = useLiveListState();// 计算属性:分组列表(每行2个)您可以在这里进行每行展示个数的设置。const groupedList = computed(() => {const list = liveList.value || [];const groups = [];for (let i = 0; i < list.length; i += 2) {groups.push(list.slice(i, i + 2));}return groups;});// 初始化onMounted(() => {fetchLiveList({ cursor: "", count: 20 });});// 加入直播const handleJoinLive = (live: any) => {uni.redirectTo({ url: `/pages/audience/index?liveID=${live.liveID}` }); // 跳转至您的目标页面};</script><style scoped>.live-list {flex: 1;background: #fff;}.list {width: 100%;}.row {flex-direction: row;padding: 0 32rpx 16rpx;justify-content: space-between;}.card {width: 48%;height: 320rpx;background: #f5f5f5;border-radius: 12rpx;overflow: hidden;}.cover {width: 100%;height: 220rpx;}.info {flex: 1;padding: 12rpx;flex-direction: column;}.title {font-size: 26rpx;font-weight: 600;color: #000;lines: 1;text-overflow: ellipsis;overflow: hidden;}.owner {font-size: 22rpx;color: #666;margin-top: 4rpx;lines: 1;text-overflow: ellipsis;overflow: hidden;}.count {font-size: 20rpx;color: #999;margin-top: 4rpx;lines: 1;text-overflow: ellipsis;overflow: hidden;}</style>
LiveInfo 参数说明
参数名 | 类型 | 描述 |
liveID | string | 直播间的唯一标识符 |
liveName | string | 直播间的标题 |
coverURL | string | 直播间的封面图片地址 |
liveOwner | 房主的个人信息 | |
totalViewerCount | number | 直播间的总观看人数 |
categoryList | [number] | 直播间的分类标签列表 |
notice | string | 直播间的公告信息 |
metaData | [string: string] | 开发者自定义的元数据,用于实现复杂的业务场景 |
功能进阶
场景一:实现直播列表的分类展示
在 App 的直播广场页,顶部设有“热门”、“音乐”、“游戏”等分类标签。用户点击不同的标签后,下方的直播列表会动态筛选,只展示对应分类的直播间,从而帮助用户快速发现感兴趣的内容。

实现方式
核心是利用
LiveInfo 模型中的 categoryList 属性。当主播开播设置分类后,fetchLiveList 返回的 LiveInfo 对象中就会包含这些分类信息。您的 App 在获取到完整的直播列表后,只需在客户端根据用户选择的分类,对这个列表进行一次简单的筛选,然后刷新 UI 即可。代码示例
以下示例展示了如何在直播列表页中增加根据一个
categoryList来处理数据和筛选逻辑的 UI。<template><view class="live-list"><!-- 分类标签栏 --><view class="category-tabs"><viewv-for="cat in categories":key="cat.id"class="tab":class="{ active: selectedCategory === cat.id }"@tap="selectedCategory = cat.id">{{ cat.name }}</view></view><!-- 直播列表 --><list class="list" @loadmore="loadMore" :show-scrollbar="false"><!-- 行循环 --><cell v-for="(row, idx) in groupedList" :key="`row-${idx}`"><view class="row"><!-- 卡片循环 --><viewv-for="live in row":key="live.liveID"class="card"@tap="handleJoinLive(live)"><image :src="live.coverURL" class="cover" /><!-- 分类标签 --><view v-if="live.liveInfo?.categoryList?.length" class="category-badge"><text class="badge-text">{{ getCategoryName(live.liveInfo.categoryList[0]) }}</text></view><view class="info"><text class="title">{{ live.liveName }}</text><text class="owner">{{ live.liveOwner?.userName }}</text><text class="count">{{ live.totalViewerCount }}人看过</text></view></view></view></cell></list></view></template><script setup lang="ts">import { computed, onMounted, ref } from 'vue';import { useLiveListState } from "@/uni_modules/tuikit-atomic-x/state/LiveListState";// 状态管理const { liveList, liveListCursor, fetchLiveList } = useLiveListState();// 本地状态const selectedCategory = ref(0); // 0 代表全部// 分类列表const categories = [{ id: 0, name: '全部' },{ id: 1, name: '游戏' },{ id: 2, name: '音乐' },{ id: 3, name: '聊天' },{ id: 4, name: '体育' },{ id: 5, name: '娱乐' },];// 分类名称映射const categoryMap: Record<number, string> = {1: '游戏',2: '音乐',3: '聊天',4: '体育',5: '娱乐',};// 获取分类名称const getCategoryName = (categoryId: number) => {return categoryMap[categoryId] || '其他';};// 计算属性:过滤分类后的列表const filteredList = computed(() => {const list = liveList.value || [];// 如果选择"全部",直接返回全部列表if (selectedCategory.value === 0) {return list;}// 根据选中的分类过滤return list.filter(live => {const categoryList = live.liveInfo?.categoryList || [];return categoryList.includes(selectedCategory.value);});});// 计算属性:分组列表(每行2个)const groupedList = computed(() => {const list = filteredList.value;const groups = [];for (let i = 0; i < list.length; i += 2) {groups.push(list.slice(i, i + 2));}return groups;});// 初始化onMounted(() => {fetchLiveList({ cursor: "", count: 20 });});// 加入直播const handleJoinLive = (live: any) => {uni.redirectTo({ url: `/pages/audience/index?liveID=${live.liveID}` }); // 跳转至您的目标页面};</script><style scoped>.live-list {flex: 1;background: #fff;}/* 分类标签栏 */.category-tabs {flex-direction: row;padding: 16rpx 32rpx;background: #f9f9f9;border-bottom: 1rpx solid #e8e8e8;overflow-x: auto;}.tab {padding: 8rpx 20rpx;margin-right: 12rpx;background: #fff;border: 1rpx solid #e0e0e0;border-radius: 20rpx;font-size: 24rpx;color: #666;white-space: nowrap;}.tab.active {background: #0468FC;border-color: #0468FC;color: #fff;}.list {width: 100%;}.row {flex-direction: row;padding: 0 32rpx 16rpx;justify-content: space-between;}.card {width: 48%;height: 320rpx;background: #f5f5f5;border-radius: 12rpx;overflow: hidden;position: relative;}.cover {width: 100%;height: 220rpx;}/* 分类徽章 */.category-badge {position: absolute;top: 8rpx;left: 8rpx;background: rgba(4, 104, 252, 0.9);border-radius: 4rpx;padding: 4rpx 8rpx;}.badge-text {font-size: 18rpx;color: #fff;font-weight: 600;}.info {flex: 1;padding: 12rpx;flex-direction: column;}.title {font-size: 26rpx;font-weight: 600;color: #000;lines: 1;text-overflow: ellipsis;overflow: hidden;}.owner {font-size: 22rpx;color: #666;margin-top: 4rpx;lines: 1;text-overflow: ellipsis;overflow: hidden;}.count {font-size: 20rpx;color: #999;margin-top: 4rpx;lines: 1;text-overflow: ellipsis;overflow: hidden;}</style>
场景二:实现语聊房内的自定义状态同步
在语聊房中,主播可能需要向所有观众同步一些自定义信息,例如“当前房间话题”、“背景音乐信息”等。
LiveListState 的 MetaData 功能可以实现这一点。实现方式
1. 主播端将自定义信息(建议使用 JSON 格式)通过
updateLiveMetaData 接口设置到一个或多个 key 中。AtomicXCore 会将这个变更实时同步给所有观众。2. 观众端只需监听
currentLive 中 metaData 的变化,一旦发现关心的 key 更新,就解析其 value 并刷新业务状态。代码示例
import { useLiveListState } from "@/uni_modules/tuikit-atomic-x/state/LiveListState";// 状态管理const { updateLiveMetaData, currentLive } = useLiveListState();// 1. 定义一个背景音乐模型const musicModel = ref({musicId: '',musicName: '',,})// 2. 主播端:在您的主播业务逻辑中,添加推送背景音乐的方法const updateBackgroundMusic= () => {updateLiveMetaData({metaData: JSON.stringify(["music_info": musicModel.value]),success: () => {console.log('背景音乐 ${musicModel.value.musicName} 推送成功')},faile: (error) => {console.log('背景音乐推送失败', error)}})}// 3. 观众端:在观众端监听 currentLivewatch( currentLive, (newVal, oldVal) => {const newMusic = JSON.parse(newVal).metaData// 在此播放音乐})
API 文档
State | 功能描述 | API 文档 |
LiveListState | 直播间全生命周期管理:创建 / 加入 / 离开 / 销毁房间,查询房间列表,修改直播信息(名称、公告等),监听直播状态(例如被踢出、结束)。 |
常见问题
语聊房的列表和视频直播的列表数据是同一份吗?
它们的数据是同一份,您不需要分开拉取。
LiveListState 是一个全局单例,它负责统一管理应用中所有“直播”房间的生命周期,无论是视频直播还是语聊房。直播列表中如何区分语聊房和视频直播
LiveListState 本身不区分房间的业务类型。您需要在获取列表后,在客户端的应用层(业务逻辑或 UI 层)进行筛选和分类。我们推荐采用以下方式进行区分:
为
liveID 添加业务前缀。这是一种可选的、纯粹的应用层约定,用于辅助您在客户端快速筛选。步骤1:创建房间时添加前缀 在您生成 liveID 并调用 createLive 时,为不同业务类型的 liveID 赋予不同的前缀。例如:视频直播的 ID 以 “Live_” 开头 (例如: Live_12345),语聊房的 ID 以 “voice_” 开头 (例如: voice_67890)。
步骤2:获取列表时检查前缀 客户端在拉取到列表后,通过检查 liveID 字符串的前缀来进行区分。
使用 updateLiveMetaData 时有哪些需要注意的限制和规则?
为了保证系统的稳定和高效,
metaData 的使用遵循以下规则:权限: 只有房主和管理员可以调用
updateLiveMetaData。普通观众没有权限。数量与大小限制:
单个房间最多支持 10 个 key。
每个 key 的长度不超过 50 字节,每个 value 的长度不超过 2KB。
单个房间所有 value 的总大小不超过 16KB。
冲突解决:
metaData 的更新机制是“后来者覆盖”。如果多个管理员在短时间内修改同一个 key,最后一次的修改会生效。建议在业务设计上避免多人同时修改同一个关键信息。