一个基于原生 HTML5 video 标签构建的轻量级、自适应 MP4 视频播放器。
本项目全程依靠 AI 工具完成需求梳理、架构设计、代码开发、文档编写,特此诚挚致谢:
-
豆包
负责全套开发规范文档生成、分阶段流程设计、API 文档与 README 排版、开源文件模板提供。
官网:https://www.doubao.com -
Trae AI
负责播放器核心代码实现、交互逻辑、UI 渲染与工程化构建。
官网:https://trae.ai
本项目遵循 Codex / Claude / Trae 标准化分阶段 AI 开发流程,严格执行阶段目标 + 验收机制,全部前置规划文档由豆包辅助生成:
-
需求与工程规范文档生成阶段
向豆包(对话历史)完整输出项目需求,由豆包生成整套 AI 协同开发规范文件:agents.md:AI 智能体行为约束、项目工程规则planning.md:分阶段开发计划、各阶段目标与验收标准SPED.md:产品规格说明书,功能、交互、API、兼容性定义.rules:代码规范、提交规范、文件约束memory/:项目记忆目录,存储需求变更、迭代记录、问题台账 所有阶段强制要求:完成当前阶段验收标准,才可进入下一开发阶段。
-
工程初始化阶段
在 Trae 编辑器创建 Vite+TS 库工程,导入豆包输出的全套规划规范文件,确认目录结构、构建配置、Git 配置无误后,启动正式编码开发。 -
分阶段编码迭代阶段
依照planning.md划分的阶段依次开发,每阶段完成后对照验收项自测;全程使用 Trae 完成核心代码编写、交互逻辑实现、分层架构落地。 -
文档与开源配套完善阶段
豆包辅助完成完整 README、.gitignore、MIT LICENSE 开源文件,统一输出标准化可直接使用的文本。
- 轻量级:零第三方播放器依赖,纯原生实现
- 自适应:根据容器宽度自动调整控制器布局
- 图标化:所有按钮采用内联 SVG 图标,无文字
- 可扩展:支持自定义按钮注入
- 交互流畅:XGPlayer 风格居中悬浮播放/暂停效果
pnpm install APMPlayer<link rel="stylesheet" href="dist/apm-player.css">
<script src="dist/apm-player.umd.js"></script>
<div id="player-container" style="width: 640px; height: 360px;"></div>
<script>
const container = document.getElementById('player-container');
const player = new APMPlayer({
container: container,
videoUrl: 'https://example.com/video.mp4',
autoplay: false,
muted: false,
});
</script>import APMPlayer from 'APMPlayer';
import 'APMPlayer/dist/apm-player.css';
const container = document.getElementById('player-container');
const player = new APMPlayer({
container: container,
videoUrl: 'https://example.com/video.mp4',
});| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| container | HTMLElement | - | 播放器容器元素 |
| videoUrl | string | - | 视频地址 |
| poster | string | - | 视频封面图 |
| autoplay | boolean | false | 是否自动播放 |
| muted | boolean | false | 是否静音 |
| loop | boolean | false | 是否循环播放 |
| showPip | boolean | true | 是否显示画中画按钮 |
| showDownload | boolean | true | 是否显示下载按钮 |
| showFullscreen | boolean | true | 是否显示样式全屏按钮 |
| showNativeFullscreen | boolean | true | 是否显示原生全屏按钮 |
| showLoading | boolean | true | 是否显示加载动画 |
| customButtons | CustomButtonConfig[] | - | 自定义按钮配置 |
// 播放
player.play();
// 暂停
player.pause();
// 切换播放/暂停
player.toggle();
// 跳转指定时间(秒)
player.seek(30);
// 设置音量(0-1)
player.setVolume(0.5);
// 切换静音
player.toggleMute();
// 切换画中画
player.togglePip();
// 下载视频
player.download();
// 切换样式全屏
player.toggleFullscreen();
// 切换原生全屏
player.toggleNativeFullscreen();
// 切换视频地址
player.setVideoUrl('new-video.mp4', 'new-poster.jpg');
// 销毁播放器
player.destroy();player.on('play', () => {
console.log('视频开始播放');
});
player.on('pause', () => {
console.log('视频暂停');
});
player.on('ended', () => {
console.log('视频播放结束');
});
player.on('timeupdate', (currentTime, duration) => {
console.log(`当前时间: ${currentTime}, 总时长: ${duration}`);
});
player.on('volumechange', (volume, muted) => {
console.log(`音量: ${volume}, 静音: ${muted}`);
});
player.on('loadedmetadata', (duration) => {
console.log(`视频元数据加载完成,时长: ${duration}`);
});
player.on('progress', (buffered) => {
console.log(`缓冲进度: ${buffered}%`);
});
player.on('error', (error) => {
console.error('播放错误:', error);
});
player.on('fullscreenchange', (isFullscreen) => {
console.log(`全屏状态: ${isFullscreen}`);
});
player.on('pipchange', (isPip) => {
console.log(`画中画状态: ${isPip}`);
});const player = new APMPlayer({
container: container,
videoUrl: 'video.mp4',
customButtons: [
{
id: 'custom-btn',
icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5z"/></svg>',
onClick: (player) => {
console.log('自定义按钮点击');
},
tooltip: '自定义按钮',
alwaysCollapsed: false,
},
],
});| 按键 | 功能 |
|---|---|
| Space | 播放/暂停 |
| ArrowLeft | 快退 5 秒 |
| ArrowRight | 快进 5 秒 |
| ArrowUp | 音量增加 10% |
| ArrowDown | 音量减少 10% |
| F | 切换原生全屏 |
| M | 切换静音 |
采用分层架构设计,确保代码的可维护性和可扩展性:
src/
├── core/ # 核心逻辑层
│ └── index.ts # 媒体核心能力封装
├── ui/ # UI 渲染层
│ └── index.ts # 控制器、悬浮图标、菜单等
├── buttons/ # 按钮管理层
│ └── index.ts # 按钮注册、收纳、渲染
├── types.ts # 类型定义
├── utils.ts # 工具函数
├── styles/ # 样式文件
│ └── index.css
└── index.ts # 播放器主类
播放器会根据容器宽度自动调整按钮布局:
- 宽度充足时,所有按钮横向展示
- 宽度不足时,自动将选配按钮和自定义按钮收纳到三点菜单中
- MORE 按钮仅在需要收纳时显示
- 视频播放中,鼠标离开播放器:自动隐藏
- 视频播放中,鼠标不动 3 秒:自动隐藏
- 视频暂停中:不自动隐藏
- 正在拖拽进度条/音量:不自动隐藏
- 更多菜单显示中:不自动隐藏
- 首次加载未播放:居中展示透明轮廓播放图标,点击播放且图标永久消失
- 播放中点击视频空白处:浮现透明轮廓暂停图标,渐变淡出消失
- 暂停中点击视频空白处:浮现透明轮廓播放图标,渐变淡出消失
- 样式全屏:容器全屏,非系统全屏,兼容更多场景
- 原生全屏:系统原生全屏,支持 ESC 键退出
所有事件监听、观察者都会在 destroy() 方法中彻底销毁,避免内存泄漏。
- TypeScript 7.0+
- Vite 8.0+
- 原生 HTML5 Video API
# 开发模式
pnpm run dev
# 生产构建
pnpm run build
# 类型检查
pnpm run typecheck
# 预览构建产物
pnpm run preview支持所有现代浏览器,包括:
- Chrome/Edge (最新版本)
- Firefox (最新版本)
- Safari (最新版本)
MIT License