概述
本文对 TUILiveKit Demo 中的观看页面进行了详细的介绍,您可以在已有项目中直接参考本文档集成我们开发好的观看页面,也可以根据您的需求按照文档中的内容对页面的样式,布局以及功能项进行深度的定制。
功能概览
功能分类 | 具体能力 |
直播视频播放 | 高清流畅的直播体验 |
弹幕互动 | 实时弹幕交流 |
观众列表 | 查看在线观众信息 |
关注主播 | 一键关注喜欢的主播 |
全屏播放 | 沉浸式观看体验 |
Web 桌面浏览器支持 | 跨平台兼容 |
功能展示
观看页面提供默认行为和风格,但如果默认行为和样式不能完全满足您的需求,您也可以对 UI 进行自定义。图中显示的数字与特定功能列表中的类别相对应。其中主要包含直播信息展示、视频直播区域、在线观众、音视频操作、直播时长、画面分辨率切换、全屏功能、聊天互动、消息列表等。

快速接入
步骤1:环境配置及开通服务
步骤2: 安装依赖
npm install tuikit-atomicx-vue3 @tencentcloud/uikit-base-component-vue3 --save
pnpm add tuikit-atomicx-vue3 @tencentcloud/uikit-base-component-vue3
yarn add tuikit-atomicx-vue3 @tencentcloud/uikit-base-component-vue3
步骤3: 观看页面接入
在您的项目下创建
live-player.vue 文件,可直接复制如下代码至您的项目中集成观看页面。<template><UIKitProvider language="zh-CN" theme="dark"><div class="live-container"><!-- 直播核心区域 --><section class="live-main"><!-- 顶部信息栏 --><div class="top-bar"><div class="top-left"><Avatar:src="currentLive?.liveOwner.avatarUrl":size="24"class="avatar"/><span class="user-name">{{ currentLive?.liveOwner.userName || currentLive?.liveOwner.userId }}</span><div class="follow-btn" @click="handleFollow"><span>关注</span></div></div><div class="top-right"><div class="audience-preview" @click="showAudienceDrawer"><Avatarv-for="(user, index) in audienceList.slice(0, 3)":key="user.userId || index":src="user.avatarUrl":size="24"class="audience-avatar"/><div class="audience-count"><span>{{ audienceList.length }}</span></div></div><IconClose class="back-btn" size="20" @click="handleBack" /></div></div><!-- 直播播放器 --><div class="stream-container"><LiveCoreView class="player" /></div><!-- 悬浮消息列表 --><div class="floating-message-list"><BarrageList class="message-list" /></div><!-- 底部消息输入 --><div class="bottom-input"><div class="message-input-wrapper"><BarrageInput:width="inputWidth"height="44px":placeholder="'说点什么...'":autoFocus="false":disabled="!isLiveActive"/></div></div></section><!-- 观众列表抽屉 --><div v-if="audienceDrawerVisible" class="audience-drawer-overlay" @click="closeAudienceDrawer"><div class="audience-drawer" @click.stop><div class="drawer-header"><h3>在线观众 ({{ audienceList.length }})</h3></div><div class="drawer-content"><LiveAudienceList class="audience-list" /><div v-if="audienceList.length === 0" class="empty-audience"><p>暂无观众在线</p></div></div></div></div><!-- 直播结束遮罩 --><div v-if="liveEndVisible" class="live-end-overlay"><div class="live-end-content"><div class="end-title"><span>直播已结束</span></div><Avatar:src="currentLive?.liveOwner.avatarUrl":size="85"class="end-avatar"/><span class="end-name">{{ currentLive?.liveOwner.userName || currentLive?.liveOwner.userId }}</span></div></div></div></UIKitProvider></template><script setup lang="ts">import { onMounted, ref, computed } from 'vue';import {LiveAudienceList,BarrageList,BarrageInput,useLiveAudienceState,LiveCoreView,useLiveState,Avatar,useLoginState} from 'tuikit-atomicx-vue3';import { UIKitProvider, IconClose } from '@tencentcloud/uikit-base-component-vue3';const { audienceList, fetchAudienceList } = useLiveAudienceState();const { currentLive } = useLiveState();const { login } = useLoginState();const audienceDrawerVisible = ref(false);const liveEndVisible = ref(false);const isLiveActive = ref(true);const inputWidth = computed(() => {return window.innerWidth > 768 ? '200px' : '158px';});async function initLogin() {try {await login({sdkAppId: 0, // SDKAppID, 可以参考步骤 1 获取userId: '', // UserID, 可以参考步骤 1 获取userSig: '', // userSig, 可以参考步骤 1 获取});} catch (error) {console.error('登录失败:', error);}}function handleBack() {console.log('返回上一页');}function handleFollow() {console.log('关注主播');}async function showAudienceDrawer() {await fetchAudienceList();audienceDrawerVisible.value = true;}function closeAudienceDrawer() {audienceDrawerVisible.value = false;}onMounted(async () => {await initLogin();});</script><style scoped>:global(body){height:100vh;width:100vw;margin:0;padding:0;overflow:hidden;font-size:14px;line-height:1.6;text-rendering:optimizeLegibility;}:global(*),:global(*::before),:global(*::after){box-sizing:border-box;margin:0;}.live-container{position:fixed;display:flex;justify-content:center;align-items:center;width:100%;height:100%;background-color:black;color:var(--text-color1,#fff);}.live-main{width:100%;height:100%;position:relative;background-color:var(--uikit-color-bg-color-dialog);}.top-bar{position:absolute;top:10px;left:0;right:0;display:flex;justify-content:space-between;align-items:center;z-index:100;height:50px;padding:0 10px;}.top-left{display:flex;align-items:center;gap:5px;max-width:55%;padding:5px;background-color:var(--uikit-color-black-6);border-radius:25px;backdrop-filter:blur(10px);overflow:hidden;}.back-btn{cursor:pointer;color:var(--text-color1,#fff);transition:color 0.2s;flex-shrink:0;}.back-btn:hover{color:#4086FF;}.avatar{border:1px solid var(--uikit-color-white-7);flex-shrink:0;}.user-name{color:var(--text-color1,#fff);font-weight:500;font-size:14px;max-width:60%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.follow-btn{display:flex;align-items:center;justify-content:center;width:50px;max-width:100px;height:24px;background-color:#4086FF;border-radius:12px;cursor:pointer;transition:background-color 0.2s;flex-shrink:0;overflow:hidden;}.follow-btn:hover{background-color:#2B6AD6;}.follow-btn span{font-size:14px;color:var(--text-color1,#fff);}.top-right{display:flex;align-items:center;gap:5px;overflow:hidden;}.audience-preview{display:flex;align-items:center;gap:1px;cursor:pointer;}.audience-avatar{border:1px solid var(--uikit-color-white-7);}.audience-count{display:flex;align-items:center;justify-content:center;width:24px;height:24px;background-color:var(--uikit-color-black-6);border-radius:50%;text-align:center;color:var(--text-color1,#fff);overflow:hidden;}.audience-count span{flex:1;font-size:12px;}.close-btn{display:flex;align-items:center;justify-content:center;width:32px;height:32px;background-color:var(--uikit-color-black-6);border-radius:50%;cursor:pointer;color:var(--text-color1,#fff);transition:background-color 0.2s;}.close-btn:hover{background-color:rgba(255,255,255,0.2);}.stream-container{width:100%;height:100%;display:flex;align-items:center;justify-content:center;}.player{width:100%;height:100%;background-color:black;}.floating-message-list{position:absolute;left:0;bottom:60px;z-index:99;pointer-events:none;}.message-list{width:100%;height:100%;overflow-y:auto;padding:8px;}.bottom-input{position:absolute;bottom:10px;left:0;right:0;display:flex;align-items:center;justify-content:space-between;height:48px;padding:0 10px;z-index:100;}.message-input-wrapper{display:flex;align-items:center;gap:8px;}.input-actions{display:flex;align-items:center;gap:4px;}.emoji-btn,.gift-btn{display:flex;align-items:center;justify-content:center;width:36px;height:36px;background-color:var(--uikit-color-black-6);border:none;border-radius:18px;color:var(--text-color1,#fff);cursor:pointer;transition:all 0.2s;font-size:16px;backdrop-filter:blur(10px);}.emoji-btn:hover,.gift-btn:hover{background-color:#4086FF;transform:scale(1.05);}.audience-drawer-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background-color:rgba(0,0,0,0.5);z-index:1000;display:flex;align-items:flex-end;justify-content:center;}.audience-drawer{width:100%;max-width:500px;height:90%;background-color:rgb(31,32,36);border-radius:20px 20px 0 0;display:flex;flex-direction:column;animation:slideUp 0.3s ease-out;}@keyframes slideUp{from{transform:translateY(100%);}to{transform:translateY(0);}}.drawer-header{display:flex;align-items:center;justify-content:space-between;padding:20px;border-bottom:1px solid #333;}.drawer-header h3{margin:0;font-size:18px;font-weight:600;color:var(--text-color1,#fff);}.close-drawer-btn{display:flex;align-items:center;justify-content:center;width:32px;height:32px;background-color:transparent;border:none;border-radius:50%;color:#999;cursor:pointer;transition:all 0.2s;}.close-drawer-btn:hover{background-color:#333;color:var(--text-color1,#fff);}.drawer-content{flex:1;overflow:hidden;position:relative;}.audience-list{height:100%;overflow-y:auto;padding:16px;}.empty-audience{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:#666;text-align:center;padding:40px 20px;}.empty-icon{font-size:48px;margin-bottom:16px;opacity:0.5;}.empty-audience p{font-size:16px;margin:0;}.live-end-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background-color:rgba(31,32,36,0.95);z-index:1000;display:flex;align-items:center;justify-content:center;}.live-end-content{display:flex;flex-direction:column;align-items:center;gap:20px;text-align:center;padding:40px;}.close-icon{position:absolute;top:20px;right:20px;display:flex;align-items:center;justify-content:center;width:40px;height:40px;background-color:rgba(255,255,255,0.1);border-radius:50%;cursor:pointer;color:#fff;transition:background-color 0.2s;}.close-icon:hover{background-color:rgba(255,255,255,0.2);}.end-title{padding-top:60px;padding-bottom:30px;}.end-title span{font-size:24px;font-weight:600;color:var(--text-color1,#fff);}.end-avatar{border:1px solid var(--uikit-color-white-7);}.end-name{font-size:16px;color:var(--text-color1,#fff);}@media screen and (orientation:landscape){.floating-message-list{width:400px;height:100px;}}@media screen and (orientation:portrait){.floating-message-list{width:260px;height:180px;}.bottom-input{padding:0 20px;}}@media (max-width:768px){.top-bar{padding:0 8px;}.top-left{max-width:70%;padding:6px 10px;}.user-name{max-width:80px;}}</style>
步骤4: 启动项目
npm run dev
自由定制
另外,我们也支持您根据项目需求对观看页面进行 UI 定制能力。主要可供定制的能力如下表所示。可供定制内容包括但不限于对源码中的颜色主题、字体、圆角、按钮、图标、输入框、弹框等内容,都可以进行增加、删除、修改等定制操作,下列分别给出颜色主题、按钮以及图标的定制示例,您可以参考实现方式通用到其他组件,满足您的 UI 定制需要。
类别 | 功能 | 描述 |
直播信息展示 | 自定义观看页面信息区域展示 | 支持: 展示/隐藏 Logo,替换为您需要的 Logo UI 定制、展示/隐藏关注按钮,替换为您需要的按钮风格 |
在线观众 | 自定义观众信息展示 | 支持: 展示/隐藏观众等级 观众信息字体、颜色 UI 自定义设置 替换为您需要的 Icon 风格 |
消息列表 | 自定义消息弹幕区域展示 | 支持: 展示/隐藏聊天输入区域 支持 UI 定制聊天气泡风格、定制观众等级等内容 |
颜色主题
参见步骤3中代码示例,您可以使用操作 theme 的值来满足您切换颜色主题。
<UIKitProvider theme="dark"> // theme 传入 dark 时,界面整体颜色主题为黑色主题xxx // theme 传入 light 时,界面整体颜色主题为白色主题</UIKitProvider>
按钮 Button / 图标 Icon
若您需要对按钮 Button 或者图标 Icon 进行新增或替换等 UI 定制,您可以通过如下方式进行实现,以观看页面操作的 Icon 为例。参考下图,您可以找到对应 Button / Icon 指定位置源码,对当前部分的按钮进行增加、删除、替换等 UI 定制操作。

播放直播流
步骤1:指定 LiveId 播放
若您需要指定 LiveId 进行播放,您需要在上述快速接入中的步骤3代码基础上增量添加如下内容,参考方式如下:
//live-player.vueimport { onMounted } from 'vue';import { useLiveState } from 'tuikit-atomicx-vue3';const { joinLive } = useLiveState();onMounted(async () => {await joinLive({ liveId: 'xxx' }); // 输入 liveId 加入直播间,具体参数含义可参考步骤 1 中的准备工作});
步骤2:路由配置
由于涉及到直播列表(或首页)到直播间的跳转逻辑,您需要配置 Vue Router。在项目
src 目录下新建 router 文件夹,并创建 index.ts 文件。然后,在您的主文件(例如 main.ts 或 index.ts)中引入并使用路由。可参考 GitHub 代码示例, 如需要直播列表,可参考文档 直播列表。//src/router/index.tsimport { createRouter, createWebHistory } from 'vue-router';const routes = [{path: '/live-player',component: () => import('../views/live-player.vue'),},// 如果需要直播列表功能,可添加如下路由// {// path: '/live-list',// component: () => import('../views/live-list.vue'),// },];const router = createRouter({history: createWebHistory(),routes,});export default router;// src/main.tsimport { createApp } from 'vue';import App from './App.vue';import router from './router';const app = createApp(App);app.use(router);app.mount('#app');