视频布局(Web)

最近更新时间:2026-05-12 16:44:01

我的收藏
本篇文档旨在指导开发者在标准会议无 UI 集成方案中实现视频画面渲染、布局切换、屏幕共享画面展示、移动端布局适配以及视频画面挂件定制。您可以直接使用 RoomView 组件承载标准会议的视频区域,也可以通过 layoutTemplateparticipantViewUI 插槽和 stream-double-click 事件组合出符合业务场景的视频布局体验。
RoomView 只负责视频流画面容器和布局编排,不包含完整会议页面、成员列表、底部工具栏或业务弹窗。会议页面通常需要将 RoomView 与房间管理、设备控制、成员管理等能力组合使用。


前提条件

用户已经通过 useLoginState 完成登录鉴权,请参考 接入概览 文档。
用户已经通过 useRoomState 进入标准会议房间,请参考 房间管理 文档。
承载 RoomView 的父容器必须具备明确的宽高,否则视频区域可能无法正常计算布局。

功能介绍

RoomView 是标准会议的视频布局容器,用于渲染成员摄像头流和屏幕共享流。开发者主要通过布局入参选择画面排列方式,通过插槽定制视频挂件,通过事件响应用户对视频画面的操作。

RoomView 组件接口

类型
名称
说明
入参
layoutTemplate?: RoomLayoutTemplate
视频布局模板。默认值为 RoomLayoutTemplate.GridLayout
插槽
participantViewUI
自定义视频画面挂件,插槽参数为 { participant, streamType }
事件
stream-double-click
用户双击视频画面时触发,事件参数为 { participant, streamType }

内置布局能力总览

标准会议中,RoomView 通过 layoutTemplate 属性控制布局。
布局
枚举值
适用端
推荐场景
表现说明
宫格布局
RoomLayoutTemplate.GridLayout
PC Web
多人讨论、日常会议、视频面试
默认布局。最多按 3 x 3 展示当前页画面,超过 9 路时支持翻页。
顶部栏布局
RoomLayoutTemplate.CinemaLayout
PC Web
演示、培训、屏幕共享
主画面居中突出,其他成员在顶部栏展示。
侧边栏布局
RoomLayoutTemplate.SidebarLayout
PC Web
演讲、汇报、主讲人模式
主画面居中突出,其他成员在侧边栏展示。
移动端布局
RoomLayoutTemplate.MobileLayout
H5
移动端会议页面
支持屏幕分享双指放大、滑动分页、主画面、悬浮画面和懒加载。

核心参数说明

参数
说明
常见用途
participant
当前视频画面对应的成员对象,包含 userIduserNamenameCardrolemicrophoneStatuscameraStatus 等状态。
展示昵称、角色标识、麦克风/摄像头状态,或判断当前画面对应的操作目标。
streamType
当前视频画面的流类型,用于区分摄像头流和屏幕共享流。
摄像头流展示成员挂件;屏幕共享流展示“正在共享屏幕”等提示,并避免展示不适合的摄像头状态 UI。

场景一:渲染视频区域

完成登录和进房后,如需在会议页面中展示标准会议的视频画面,可直接渲染 RoomView。这是接入视频布局能力的最小使用方式。

实现思路

为视频区域准备一个有明确宽高的容器,并在其中渲染 RoomView。如果不传入 layoutTemplate,默认使用 RoomLayoutTemplate.GridLayout

PC Web 示例代码

<template>
<div class="room-view-wrapper">
<RoomView :layout-template="RoomLayoutTemplate.GridLayout" />
</div>
</template>

<script setup lang="ts">
import { RoomLayoutTemplate, RoomView } from 'tuikit-atomicx-vue3/room';
</script>

<style scoped>
/* 必须为 RoomView 父容器明确设置宽高 */
.room-view-wrapper { width: 100%; height: 100%; }
</style>

H5 示例代码

<template>
<div class="room-view-wrapper">
<RoomView :layout-template="RoomLayoutTemplate.MobileLayout" />
</div>
</template>

<script setup lang="ts">
import { RoomLayoutTemplate, RoomView } from 'tuikit-atomicx-vue3/room';
</script>

<style scoped>
/* 必须为 RoomView 父容器明确设置宽高 */
.room-view-wrapper { width: 100%; height: 100%; }
</style>

注意事项

RoomView 会占满父容器,请确保父容器设置了明确的 widthheight
RoomView 不负责创建或加入房间,也不负责打开本地摄像头或麦克风。设备打开逻辑请参考设备及网络

场景二:自定义视频区域挂件

如果您需要在视频画面上展示昵称、头像、角色标识、麦克风状态、音量波动、屏幕共享标识或业务标签,可以使用 participantViewUI 插槽。


实现思路

RoomView 会在每个视频画面上透传 participantstreamType。业务侧可以基于成员状态渲染挂件 UI,但不需要接管视频流播放逻辑。

插槽参数

参数
类型
说明
participant
RoomParticipant
当前视频画面对应的成员,包含 userIduserNamenameCardrolemicrophoneStatus 等状态。
streamType
VideoStreamType
当前画面类型,常见值为摄像头流和屏幕共享流。

示例代码

会议页面示例:
<template>
<RoomView :layout-template="currentLayout">
<template #participantViewUI="{ participant, streamType }">
<ParticipantViewUI
:participant="participant"
:stream-type="streamType"
/>
</template>
</RoomView>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import {
RoomLayoutTemplate,
RoomView,
} from 'tuikit-atomicx-vue3/room';
import ParticipantViewUI from './ParticipantViewUI.vue';

const currentLayout = ref(RoomLayoutTemplate.GridLayout);
</script>
ParticipantViewUI.vue 示例:
<template>
<div
class="participant-view-ui"
:class="{ 'camera-off': shouldShowCameraPlaceholder }"
>
<div v-if="shouldShowCameraPlaceholder" class="camera-placeholder">
{{ displayName }}
</div>
<div class="participant-info">
<span class="user-name">{{ displayName }}</span>
<span v-if="isOwner && isCameraStream" class="role-tag">房主</span>
<span v-if="isScreenStream" class="stream-tag">{{ displayName }} 正在屏幕分享</span>
<span v-else class="device-tag">{{ isMicrophoneOn ? '麦克风已开' : '麦克风已关' }}</span>
</div>
</div>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import {
DeviceStatus,
RoomParticipantRole,
VideoStreamType,
} from 'tuikit-atomicx-vue3/room';
import type { RoomParticipant } from 'tuikit-atomicx-vue3/room';

const props = defineProps<{
participant: RoomParticipant;
streamType: VideoStreamType;
}>();

const displayName = computed(() => props.participant.nameCard || props.participant.userName || props.participant.userId);
const isOwner = computed(() => props.participant.role === RoomParticipantRole.Owner && props.streamType === VideoStreamType.Camera);
const isCameraStream = computed(() => props.streamType === VideoStreamType.Camera);
const isScreenStream = computed(() => props.streamType === VideoStreamType.Screen);
const isMicrophoneOn = computed(() => props.participant.microphoneStatus === DeviceStatus.On);
const shouldShowCameraPlaceholder = computed(() => isCameraStream.value && props.participant.cameraStatus !== DeviceStatus.On);
</script>

<style scoped>
/* 必须设置 pointer-events 属性值为 none,否则会拦截底层视频画面的双击、拖拽交互! */
.participant-view-ui { position: absolute; inset: 0; pointer-events: none; }
.participant-view-ui.camera-off { background: #1f2937; }
.camera-placeholder { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; color: #fff; font-size: 16px; }
.participant-info { position: absolute; left: 8px; bottom: 8px; display: flex; align-items: center; gap: 6px; max-width: calc(100% - 16px); padding: 4px 8px; color: #fff; background: rgb(0 0 0 / 50%); border-radius: 12px; }
.user-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
</style>

推荐做法

建议区分摄像头流和屏幕共享流。屏幕共享画面通常不需要展示麦克风图标,但可以展示“正在共享屏幕”等标识。
建议为挂件容器设置 pointer-events: none,避免遮挡视频画面的双击、拖拽或其他交互。

场景三:根据会议场景切换布局

不同会议场景对视频布局的要求不同。例如,多人讨论适合宫格布局;屏幕共享、培训或主讲人场景适合顶部栏或侧边栏布局;移动端页面适合移动端布局。

实现思路

在业务层维护当前布局状态,并将其传入 RoomViewlayoutTemplate。PC Web 可以在宫格、顶部栏、侧边栏之间切换;H5 建议固定使用 RoomLayoutTemplate.MobileLayout

示例代码

<template>
<RoomView :layout-template="currentLayout" />
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { RoomView, RoomLayoutTemplate } from 'tuikit-atomicx-vue3/room';

const currentLayout = ref(RoomLayoutTemplate.GridLayout);

function switchToGridLayout() {
currentLayout.value = RoomLayoutTemplate.GridLayout;
}

function switchToSpeakerLayout() {
currentLayout.value = RoomLayoutTemplate.SidebarLayout;
}
</script>

注意事项

PC Web 不建议使用 MobileLayout,H5 不建议使用 PC 的宫格、顶部栏或侧边栏布局。
如果业务侧提供布局切换按钮,应在 UI 层根据当前平台只展示可用布局。

场景四:屏幕共享时自动切换布局

当会议中有人开始屏幕共享时,业务通常希望自动突出共享内容;当共享结束或只剩一个画面时,再恢复到宫格布局。

实现思路

通过 useRoomParticipantState 获取 participantWithScreenparticipantList。当 participantWithScreen 从空变为有值时,将布局切换为 RoomLayoutTemplate.SidebarLayoutRoomLayoutTemplate.CinemaLayout;当画面数量恢复到 1 时,切回宫格布局。

关键接口 / 状态

状态
说明
participantWithScreen
当前正在屏幕共享的成员。
participantList
当前房间成员列表。
RoomLayoutTemplate.SidebarLayout
侧边栏主画面布局。
RoomLayoutTemplate.GridLayout
宫格布局。

示例代码

<template>
<RoomView :layout-template="currentLayout" />
</template>

<script setup>
import { ref, watch } from 'vue';
import {
RoomLayoutTemplate,
useRoomParticipantState,
} from 'tuikit-atomicx-vue3/room';

const currentLayout = ref(RoomLayoutTemplate.GridLayout);

const { participantList, participantWithScreen } = useRoomParticipantState();

watch(participantWithScreen, (newVal, oldVal) => {
if (newVal && !oldVal) {
currentLayout.value = RoomLayoutTemplate.SidebarLayout;
}
});

watch(
() => participantList.value.length + (participantWithScreen.value ? 1 : 0),
(count) => {
if (count === 1) {
currentLayout.value = RoomLayoutTemplate.GridLayout;
}
},
);
</script>

RoomView 核心逻辑说明

本节用于解释 RoomView 的内部表现,帮助开发者理解“为什么画面这样排序”“为什么某些远端画面没有持续播放”“为什么小窗口画质较低”。如果您只需要完成基础接入,可以先阅读前面的场景章节。

RoomView 核心逻辑

核心逻辑
说明
业务侧是否需要处理
视频流排序
根据屏幕共享、房主、本地用户、管理员、摄像头和麦克风状态生成视频流列表。
通常不需要。只有自定义成员列表或业务排序时才需要参考。
非可视区域不播放
视频画面支持懒加载,非可视区域中的远端视频流不会持续播放。
通常不需要。注意不要用自定义样式破坏布局容器的可视区域计算。
小窗口订阅低清流
视频流会根据画面尺寸和页面中的大画面数量选择合适清晰度,小窗口优先使用低清流,大画面和屏幕共享优先使用高清流。
通常不需要。业务侧不建议自行频繁切换远端流清晰度。
只负责排版和缩放
RoomView 负责视频画面的排版、缩放和渲染参数,不负责进房、开关设备、成员会控或业务弹窗。
需要业务侧与房间管理、设备管理、成员管理组合。

视频流排序参考

优先级
排序因素
说明
1
屏幕共享流
有屏幕共享时,屏幕共享流会优先进入视频流列表。
2
房主
房主画面优先。
3
本地用户
本地用户画面优先。
4
管理员
管理员画面优先。
5
同时开启摄像头和麦克风
音视频活跃成员优先。
6
开启摄像头
有视频画面的成员优先。
7
开启麦克风
仅音频活跃成员次之。

主画面选择规则

布局
主画面规则
宫格布局
不区分主画面,按分页展示视频流。
顶部栏 / 侧边栏布局
优先展示用户双击锁定的画面;否则展示屏幕共享;否则展示第一个开启摄像头的成员;再否则展示本地用户。
移动端布局
优先展示屏幕共享;1-2 人场景突出远端或当前主要画面;多人场景通过分页展示。
说明:
顶部栏和侧边栏布局中,用户双击某个画面后,该画面会成为主画面。若该成员离开房间,或被锁定的屏幕共享结束,主画面会自动回退到默认选择规则。

异常排查指引

视频布局本身通常不直接抛出业务错误,但可能因为房间状态、容器尺寸、设备状态或布局配置不正确导致画面不符合预期。建议按以下方式排查。
常见表现
问题类型
建议处理方式
RoomView 没有画面
未进入房间或未打开摄像头
确保在进房接口调用成功后再渲染 RoomView 组件。
确认已经打开本地摄像头,设备开启逻辑参考设备及网络
视频区域不可见或尺寸异常
父容器无尺寸
检查浏览器控制台元素,确认 RoomView 外层 divwidthheight 是否计算为 0,建议设置为 100% 或具体的 px 值。
布局没有按预期切换
布局枚举错误
使用 RoomLayoutTemplate 枚举,不要手写字符串。
PC 端或者移动端交互不符合预期
平台布局不匹配
H5 使用 RoomLayoutTemplate.MobileLayout
共享内容没有成为主画面
屏幕共享未突出展示
监听 participantWithScreen,在共享开始时切换到顶部栏或侧边栏布局。
双击或屏幕分享双指放大不生效
挂件遮挡交互
挂件层避免拦截事件,必要时设置 pointer-events: none

API 文档

Component / State
功能描述
API 文档
RoomView
标准会议视频布局主容器,负责视频流展示、布局编排、插槽透传和双击事件。
useRoomState
获取当前房间信息,用于判断是否已经进入标准会议房间。
useRoomParticipantState
提供 participantListparticipantWithScreenparticipantListWithVideo 等布局辅助状态。

常见问题

RoomView 是否会自动打开摄像头和麦克风?

不会。RoomView 负责视频画面渲染和布局编排,打开或关闭本地摄像头、麦克风需要使用设备管理相关接口。

RoomView 是否包含默认昵称、麦克风图标和角色标识?

RoomView 只提供 participantViewUI 插槽,不内置固定业务挂件。您可以根据 participantstreamType 自定义昵称、角色、麦克风状态和业务标签。

为什么页面中看不到视频布局?

常见原因包括尚未进入房间、父容器没有明确尺寸、当前平台使用了不合适的布局,或本地及远端成员没有打开摄像头。建议先确认 currentRoom、父容器宽高和设备状态。

屏幕共享时应该使用哪种布局?

PC Web 推荐使用 RoomLayoutTemplate.SidebarLayoutRoomLayoutTemplate.CinemaLayout,让共享内容成为主画面。H5 推荐继续使用 RoomLayoutTemplate.MobileLayout

顶部栏布局和侧边栏布局有什么区别?

两者都属于主画面布局。顶部栏布局将其他成员放在主画面上方,侧边栏布局将其他成员放在主画面侧边。选择哪一种主要取决于业务页面的空间结构和用户习惯。

宫格布局最多展示多少路画面?

PC Web 宫格布局单页最多展示 9 路画面,超过后通过翻页展示。移动端布局采用滑动分页方式展示。

RoomView 提供的布局均不满足需求,是否可以提供更多的可选布局?

如果 RoomView 内置布局不满足您的需求,请 联系我们 获取更多视频流布局信息。