代码演示
如何引入
import { VideoPlayer } from '@fibrous/semi-ui-solid';
基本用法
基本使用,通过 src 传入视频地址, 通过 poster 传入视频封面地址

代码
import { VideoPlayer } from '@fibrous/semi-ui-solid';
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
export default function VideoPlayerDemo() {
return <VideoPlayer height={630} src={src} poster={poster} />;
}设置菜单栏功能
通过 controlsList 设置菜单栏的展示项,该项接受值为数组,默认值为['play', 'next', 'time', 'volume', 'playbackRate', 'quality', 'route', 'mirror', 'fullscreen', 'pictureInPicture']
控件在 controlsList 允许、并且它所依赖的属性已提供时才显示:next 需要 onNext,quality 需要非空的 qualityList,route 需要非空的 routeList;其余控件只看 controlsList。
onNext 是函数 prop,传入它且 controlsList 包含 next 时才显示「下一个」按钮,点击时调用该函数。

代码
import { VideoPlayer } from '@fibrous/semi-ui-solid';
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
export default function VideoPlayerDemo() {
return <VideoPlayer height={630} src={src} poster={poster} controlsList={['play', 'time', 'volume', 'playbackRate', 'fullscreen']} />;
}循环播放
通过 loop 设置循环播放

代码
import { VideoPlayer } from '@fibrous/semi-ui-solid';
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
export default function VideoPlayerDemo() {
return <VideoPlayer height={630} src={src} poster={poster} loop />;
}快进快退
通过 seekTime 设置快进快退时间,通过键盘左右键执行快进快退

代码
import { createSignal } from 'solid-js';
import { Select, VideoPlayer } from '@fibrous/semi-ui-solid';
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
const optionList = [
{ label: '5s', value: 5 },
{ label: '10s', value: 10 },
{ label: '15s', value: 15 },
];
export default function VideoPlayerDemo() {
const [seekTime, setSeekTime] = createSignal(5);
return (
<div>
<div>
<span style={{ 'margin-bottom': '10px' }}>请选择快进快退时间</span>
<Select
aria-label="请选择快进快退时间"
value={seekTime()}
style={{ width: '100px', 'margin-left': '10px' }}
onChange={(value) => {
if (typeof value === 'number') setSeekTime(value);
}}
optionList={optionList}
placeholder="请选择快进快退时间"
/>
</div>
<VideoPlayer height={630} style={{ 'margin-top': '10px' }} src={src} poster={poster} seekTime={seekTime()} />
</div>
);
}播放速率
通过 playbackRateList 设置速率选择列表。速率、清晰度与线路控件都是原生按钮,用 Tab 聚焦即展开菜单,键盘操作见「键盘和焦点」。按钮名称为用途加当前选项(如「倍速 1.0x」),菜单项是单选项

代码
import { VideoPlayer } from '@fibrous/semi-ui-solid';
const playbackRateList = [
{ label: '0.5x', value: 0.5 },
{ label: '1.0x', value: 1 },
{ label: '1.5x', value: 1.5 },
{ label: '2.0x', value: 2 },
];
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
export default function VideoPlayerDemo() {
return <VideoPlayer height={630} src={src} poster={poster} playbackRateList={playbackRateList} />;
}音量设置
通过 volume 设置初始音量,值区间为 0 - 100, 设置 muted 为 true 可以静音播放。用户调整音量时会调用 onVolumeChange

代码
import { VideoPlayer } from '@fibrous/semi-ui-solid';
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
export default function VideoPlayerDemo() {
return <VideoPlayer height={630} src={src} poster={poster} muted />;
}清晰度切换
通过 qualityList 设置清晰度选择列表,defaultQuality 设置初始选择的清晰度,onQualityChange 设置点击后更新的 src 逻辑。
线路切换同理,通过 routeList 设置线路选择列表,defaultRoute 设置初始选择的线路,onRouteChange 设置点击后更新的 src 逻辑。

代码
import { createSignal } from 'solid-js';
import { VideoPlayer } from '@fibrous/semi-ui-solid';
const playList = [
{
src: '/assets/video/vchart-show-video.mp4',
quality: '1080p',
},
{
src: '/assets/video/vchart-show-video.mp4',
quality: '480p',
},
];
const poster = '/assets/poster2.jpeg';
const qualityList = [
{ label: '1080p', value: '1080p' },
{ label: '480p', value: '480p' },
];
export default function VideoPlayerDemo() {
const [src, setSrc] = createSignal(playList[0].src);
const updateVideoSource = (quality: string) => {
const source = playList.find((item) => item.quality === quality);
if (source) setSrc(source.src);
};
return (
<VideoPlayer
height={630}
src={src()}
poster={poster}
defaultQuality="1080p"
qualityList={qualityList}
onQualityChange={(quality) => {
console.log('quality change', quality);
updateVideoSource(quality);
}}
/>
);
}章节标记
通过 markers 设置章节标记点

代码
import { VideoPlayer } from '@fibrous/semi-ui-solid';
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
const markers = [
{
start: 0,
title: '片头',
},
{
start: 4,
title: '功能介绍',
},
{
start: 38,
title: 'Figma Plugin',
},
{
start: 51,
title: '片尾',
},
];
export default function VideoPlayerDemo() {
return <VideoPlayer height={630} src={src} poster={poster} markers={markers} />;
}主题
通过 theme 设置主题, 主题仅影响背景色

代码
import { VideoPlayer } from '@fibrous/semi-ui-solid';
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
export default function VideoPlayerDemo() {
return <VideoPlayer src={src} poster={poster} height={630} theme="light" />;
}使用 ref 控制
通过 ref 传入回调函数,回调以原生 video 元素被调用,可以实现更灵活的控制,例如多个视频同步播放/暂停


代码
import { Button, VideoPlayer } from '@fibrous/semi-ui-solid';
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
export default function VideoPlayerDemo() {
let video1: HTMLVideoElement | undefined;
let video2: HTMLVideoElement | undefined;
const handlePlayAll = () => {
void video1?.play();
void video2?.play();
};
const handlePauseAll = () => {
video1?.pause();
video2?.pause();
};
return (
<div>
<div style={{ 'margin-bottom': '12px' }}>
<Button onClick={handlePlayAll} style={{ 'margin-right': '8px' }}>
同时播放
</Button>
<Button onClick={handlePauseAll}>同时暂停</Button>
</div>
<div style={{ display: 'flex', gap: '12px' }}>
<VideoPlayer ref={(element) => (video1 = element)} src={src} poster={poster} height={315} width="50%" />
<VideoPlayer ref={(element) => (video2 = element)} src={src} poster={poster} height={315} width="50%" />
</div>
</div>
);
}键盘和焦点
- 焦点在播放器内时,空格键切换播放与暂停,焦点在按钮或输入控件上时空格键交给该控件;左右方向键按
seekTime快退、快进,焦点在输入控件、进度条或菜单内时方向键交给它们。带 Alt、Ctrl、Meta 的组合键不处理。 - 进度条是滑块(
role="slider"),用方向键按seekTime增减,PageUp、PageDown 按总时长的十分之一增减,Home、End 跳到两端。读屏读出的是「当前时长 / 总时长」。 - 倍速、清晰度、线路按钮用 Tab 聚焦即展开菜单,下、上方向键把焦点移到菜单的第一项、最后一项;菜单内用上下方向键与 Home、End 移动,Enter 或空格确认,Esc 关闭并回到按钮。
- 音量按钮获得焦点时展开音量弹层,Enter 或空格切换静音;下方向键把焦点移进弹层,音量滑块用方向键调节。
- 播放中指针离开播放器后,控制栏内有键盘焦点时控制栏保持显示。
API
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| autoPlay | 是否自动播放。 | boolean | false |
| captionsSrc | 字幕资源地址,传入后默认显示字幕。 | string | - |
| clickToPlay | 点击视频画面时是否切换播放与暂停。 | boolean | true |
| controlsList | 控制栏展示的控件,默认展示全部。控件还要满足依赖的属性已提供才会显示。 | VideoControl[] | Type["play", "next", "time", "volume", "playbackRate", "quality", "route", "mirror", "fullscreen", "pictureInPicture"] |
| crossOrigin | video 元素的 CORS 设置,允许的值为 anonymous 与 use-credentials,空串等同 anonymous。 | '' | 'anonymous' | 'use-credentials' | - |
| defaultPlaybackRate | 初始播放倍率,仅在挂载时读取。 | number | 1 |
| defaultQuality | 初始清晰度,仅在挂载时读取。 | string | - |
| defaultRoute | 初始线路,仅在挂载时读取。 | string | - |
| height | 播放器高度,数字按像素处理,字符串原样使用。 | number | string | - |
| loop | 是否循环播放。 | boolean | false |
| markers | 章节标记,每项含起始时间 start(秒)与标题 title。 | VideoPlayerMarker[] | - |
| muted | 是否静音播放,仅在挂载时读取。 | boolean | false |
| onNext | 点击下一个按钮时调用,不带参数。设置后且 controlsList 包含 next 时才显示该按钮。 | Type() => void | - |
| onPause | 暂停时调用。 | Type() => void | - |
| onPlay | 开始播放时调用。 | Type() => void | - |
| onQualityChange | 切换清晰度时调用,参数为所选清晰度的值。 | Type(quality: string) => void | - |
| onRateChange | 切换倍速时调用,参数为所选倍率。 | Type(rate: number) => void | - |
| onRouteChange | 切换线路时调用,参数为所选线路的值。 | Type(route: string) => void | - |
| onVolumeChange | 用户拖动音量滑块或切换静音时调用,参数为变化后的音量,静音时为 0;初始化不调用。 | Type(volume: number) => void | - |
| playbackRateList | 倍速选项列表,默认为 2.0、1.5、1.25、1.0、0.75 五档。 | TypeVideoPlayerOption<number>[] | - |
| poster | 封面图地址。 | string | - |
| qualityList | 清晰度选项列表,非空时才显示清晰度控件。 | TypeVideoPlayerOption<string>[] | - |
| ref | 接收原生 video 元素,用于更灵活的控制。传入函数时以该元素调用。 | TypeHTMLVideoElement | ((element: HTMLVideoElement) => void) | - |
| routeList | 线路选项列表,非空时才显示线路控件。 | TypeVideoPlayerOption<string>[] | - |
| seekTime | 快进快退一次的秒数。 | number | 10 |
| src | 视频地址。未设置时显示资源缺失提示;移除后 video 元素保留上一个地址。 | string | - |
| style | 根元素的内联样式,写在 width、height 之后,同名属性以它为准。 | JSX.CSSProperties | string | - |
| theme | 主题,仅影响背景色,可选 dark 或 light。 | VideoPlayerTheme | "dark" |
| volume | 初始音量,取值 0 到 100,仅在挂载时读取。 | number | 100 |
| width | 播放器宽度,数字按像素处理,字符串原样使用。 | number | string | - |
class、style 与原生属性和事件(如 id、aria-*、onClick、onMouseEnter)落在根元素 div 上,style 中的 width、height 覆盖 width、height 属性;根元素带 aria-label 或 aria-labelledby 时自动加 role="group",自己传 role 则以传入的为准。ref 指向的是 video 元素而不是根元素。媒体事件(timeupdate、ended 等)不会冒泡到根元素,因此不支持在组件上监听,需要时通过 ref 取得原生元素后自行监听。
Marker
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| start | 起始时间点 | number | - |
| title | 标题 | string | - |
VideoPlayerOption
playbackRateList 的选项类型为 VideoPlayerOption<number>,qualityList、routeList 的选项类型为 VideoPlayerOption<string>,value 的类型即泛型参数。
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| label | 菜单中显示的名称 | string | - |
| value | 选项值,回调参数取此 | T | - |
设计变量
| Sass 变量 | 值 | 用法 |
|---|---|---|
| $animation_duration-videoPlayer_controls-show | 500ms | videoPlayer菜单栏-弹出动画-动画持续时间 |
| $animation_duration-videoPlayer_slider-in | 300ms | videoPlayer进度条-弹出动画-动画持续时间 |
| $animation_function-videoPlayer_slider-in | cubic-bezier(0.62, 0.05, 0.36, 0.95) | videoPlayer进度条-弹出动画-动画插值函数 |
| $animation_function-videoPlayer_slider-out | cubic-bezier(0.62, 0.05, 0.36, 0.95) | videoPlayer进度条-收起动画-动画插值函数 |
| $color-videoPlayer_theme_dark-text | var(--semi-color-bg-0) | dark theme 字体色 |
| $color-videoPlayer_theme_dark-bg | var(--semi-grey-8) | dark theme 背景色 |
| $color-videoPlayer_theme_light-text | var(--semi-grey-8) | light theme 字体色 |
| $color-videoPlayer_theme_light-bg | var(--semi-color-disabled-bg) | light theme 背景色 |
| $color-videoPlayer_pause-bg | var(--semi-color-text-1) | 暂停按钮颜色 |
| $color-videoPlayer_notification-bg | var(--semi-color-overlay-bg) | notification 背景色 |
| $color-videoPlayer_notification-text | var(--semi-color-default) | notification 字体色 |
| $color-videoPlayer_controls-bg | rgba(28, 31, 35, 0.8) | 控制栏背景色 |
| $color-videoPlayer_controls-text | #fff | 控制栏文字色 |
| $color-videoPlayer_controls_popup-bg | rgb(46, 50, 56) | 音量弹层与菜单背景色 |
| $color-videoPlayer_controls_item_popup-bg-default | var(--semi-color-overlay-bg) | 控制栏弹层背景色 |
| $color-videoPlayer_controls_item_popup-bg-hover | rgba(67, 68, 74, 1) | 控制栏弹层背景色 - hover |
| $color-videoPlayer_controls_popup_item-text-default | rgba(#fff, 0.7) | 控制栏文字色 |
| $color-videoPlayer_controls_popup_item-text-active | var(--semi-color-primary) | 控制栏弹层文字色 - 选中 |
| $color-videoPlayer_progress_bar-bg-played | var(--semi-color-primary) | 进度条已播放部分背景色 |
| $color-videoPlayer_progress_bar-bg-loaded | var(--semi-grey-3) | 进度条已加载部分背景色 |
| $color-videoPlayer_progress_bar-bg-unplayed | var(--semi-grey-5) | 进度条未播放部分背景色 |
| $color-videoPlayer_progress_bar_handle-bg | #fff | handle 背景色 |
| $color-videoPlayer_progress_bar_handle-border | var(--semi-color-primary) | handle 边框色 |
| $color-videoPlayer_progress_bar_handle-shadow | var(--semi-color-shadow) | handle 阴影色 |
| $height-videoPlayer_progress_bar_hotSpot-default | 20px | 进度条热区 default 高度 |
| $height-videoPlayer_progress_bar-default | 4px | 进度条 default 高度 |
| $height-videoPlayer_progress_bar-hover | 10px | 进度条 hover 高度 |
| $height-videoPlayer_progress_bar_handle | 16px | 进度条 handle 高度 |
| $height-videoPlayer_controls_menu-default | 56px | 控制栏 default 高度 |
| $height-videoPlayer_controls_volume-default | 168px | 控制栏音量 default 高度:标题 36px + 滑块 120px + 底部留白 12px |
| $height-videoPlayer_controls_popup-default | 24px | 控制栏弹层类元素 default 高度 |
| $height-videoPlayer_controls_popup_item-default | 32px | 控制栏弹层类元素 item default 高度 |
| $width-videoPlayer_controls_volume-default | 40px | 控制栏音量 default 宽度 |
| $width-videoPlayer_controls_popup_item-default | 50px | 控制栏弹层类元素 default 宽度 |
| $width-videoPlayer_controls_popup-default | 48px | 控制栏弹层 default 宽度 |
| $spacing-videoPlayer-progress_bar_chapter-marginRight | 2px | 进度条分节间距 |
| $spacing-videoPlayer_notification-bottom | 22px | notification 距离菜单栏距离 |
| $spacing-videoPlayer_notification-left | 8px | notification 距离菜单栏左侧距离 |
| $spacing-videoPlayer_notification_text-paddingY | 8px | notification 文字垂直方向 padding |
| $spacing-videoPlayer_notification_text-paddingX | 12px | notification 文字水平方向 padding |
| $spacing-videoPlayer-controls-padding | $spacing-base-tight $spacing-base | 控制栏 padding |
| $spacing-videoPlayer-controls_item-gap | $spacing-tight | 控制栏 item 间距 |
| $spacing-videoPlayer-controls_time-paddingX | 8px | 控制栏时间 paddingX |
| $spacing-videoPlayer-controls_volume_title-paddingX | 10px | 控制栏音量标题文字 paddingX |
| $spacing-videoPlayer-controls_volume_title-paddingY | 0px | 控制栏音量标题文字 paddingX |
| $spacing-videoPlayer-controls_volume_popup-paddingY | 0px | 控制栏音量弹层 paddingX |
| $spacing-videoPlayer-controls_volume_popup-paddingX | $spacing-extra-tight | 控制栏音量弹层 paddingX |
| $spacing-videoPlayer-controls_popup-paddingX | $spacing-tight | 控制栏弹层元素 paddingX |
| $spacing-videoPlayer-controls_popup-paddingY | 0px | 控制栏弹层元素 paddingY |
| $spacing-videoPlayer-progress_bar_wrapper-marginX | $spacing-tight | 进度条 wrapper marginX |
| $spacing-videoPlayer-progress_bar_wrapper-marginY | 0px | 进度条 wrapper marginY |
| $spacing-videoPlayer_progress_bar-centerY | $height-videoPlayer_progress_bar_hotSpot-default - $height-videoPlayer_progress_bar-default * 0.5 | 进度条与 handle 的中心线距热区顶部的距离,悬停变粗时上下对称 |
| $spacing-videoPlayer_error_svg-marginBottom | 12px | error svg marginBottom |
| $radius-videoPlayer_notification | 3px | notification 圆角 |
| $radius-videoPlayer_progress_bar_handle | 50% | 进度条 handle 圆角 |
| $radius-videoPlayer_progress_bar | 999px | 进度条圆角 |
| $radius-videoPlayer_controls_item | 3px | 控制栏 item 圆角 |
| $radius-videoPlayer_controls_popup | 4px | 控制栏弹层圆角 |
| $font-videoPlayer_notification-fontSize | $font-size-regular | notification 字体大小 |
| $font-videoPlayer_controls_item-fontSize | $font-size-small | 控制栏 item 字体大小 |
| $font-videoPlayer_controls_time_text-fontSize | $font-size-regular | 控制栏时间字体大小 |
| $font-videoPlayer_error-fontSize | $font-size-regular | error 字体大小 |
| $font-videoPlayer_notification-lineHeight | 20px | notification 行高 |
| $font-videoPlayer_controls_popup_item-lineHeight | 16px | 控制栏 item 行高 |
| $font-videoPlayer_controls_popup_item-fontWeight | 600 | 控制栏 item 字体粗细 |
| $font-videoPlayer_error-fontWeight | 600 | error 字体粗细 |