feat(video): improve video playback with cross-fade transition

Implement smooth transition between videos using CSS opacity animation
Add support for multiple video elements to enable seamless switching
This commit is contained in:
你的名字
2025-07-16 14:43:33 +08:00
parent c368680eaa
commit e3a776b381
3 changed files with 70 additions and 28 deletions

View File

@@ -11,11 +11,16 @@
<body> <body>
<!-- 视频背景 --> <!-- 视频背景 -->
<video autoplay muted id="bg-video"> <div class="video-container">
<!-- 初始可以留空,或放一个默认视频 --> <video autoplay muted class="bg-video active" id="video1">
<source id="video-source" src="视频资源/3D 建模图片制作.mp4" type="video/mp4"> <source src="视频资源/3D 建模图片制作.mp4" type="video/mp4">
Your browser does not support the video tag. Your browser does not support the video tag.
</video> </video>
<video muted class="bg-video" id="video2">
<source src="" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
<!-- 内容层,覆盖在视频之上 --> <!-- 内容层,覆盖在视频之上 -->
<div class="content-overlay"> <div class="content-overlay">

View File

@@ -1,11 +1,14 @@
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
// 获取需要的 DOM 元素 // 获取需要的 DOM 元素
const bgVideo = document.getElementById('bg-video'); let video1 = document.getElementById('video1');
const videoSource = document.getElementById('video-source'); let video2 = document.getElementById('video2');
const micButton = document.getElementById('mic-button'); const micButton = document.getElementById('mic-button');
const favorabilityBar = document.getElementById('favorability-bar'); const favorabilityBar = document.getElementById('favorability-bar');
let activeVideo = video1;
let inactiveVideo = video2;
// 视频列表 // 视频列表
const videoList = [ const videoList = [
'视频资源/3D 建模图片制作.mp4', '视频资源/3D 建模图片制作.mp4',
@@ -13,25 +16,45 @@ document.addEventListener('DOMContentLoaded', function() {
'视频资源/生成加油视频.mp4' '视频资源/生成加油视频.mp4'
]; ];
// --- 视频随机播放功能 --- // --- 视频交叉淡入淡出播放功能 ---
bgVideo.addEventListener('ended', function() { function switchVideo() {
// 获取当前播放的视频 // 1. 选择下一个视频
const currentVideo = videoSource.getAttribute('src'); const currentVideoSrc = activeVideo.querySelector('source').getAttribute('src');
let nextVideoSrc = currentVideoSrc;
// 过滤掉当前视频,从剩下的视频中随机选择一个 while (nextVideoSrc === currentVideoSrc) {
let nextVideo = currentVideo;
while (nextVideo === currentVideo) {
const randomIndex = Math.floor(Math.random() * videoList.length); const randomIndex = Math.floor(Math.random() * videoList.length);
nextVideo = videoList[randomIndex]; nextVideoSrc = videoList[randomIndex];
} }
// 设置新的视频源并播放 // 2. 设置不活动的 video 元素的 source
videoSource.setAttribute('src', nextVideo); inactiveVideo.querySelector('source').setAttribute('src', nextVideoSrc);
bgVideo.load(); inactiveVideo.load();
bgVideo.play().catch(error => {
// 3. 当不活动的视频可以播放时,执行切换
inactiveVideo.addEventListener('canplaythrough', function onCanPlayThrough() {
// 确保事件只触发一次
inactiveVideo.removeEventListener('canplaythrough', onCanPlayThrough);
// 4. 播放新视频
inactiveVideo.play().catch(error => {
console.error("Video play failed:", error); console.error("Video play failed:", error);
}); });
});
// 5. 切换 active class 来触发 CSS 过渡
activeVideo.classList.remove('active');
inactiveVideo.classList.add('active');
// 6. 更新角色
[activeVideo, inactiveVideo] = [inactiveVideo, activeVideo];
// 为新的 activeVideo 绑定 ended 事件
activeVideo.addEventListener('ended', switchVideo, { once: true });
}, { once: true }); // 使用 { once: true } 确保事件只被处理一次
}
// 初始启动
activeVideo.addEventListener('ended', switchVideo, { once: true });
// --- 麦克风按钮交互和好感度条模拟 --- // --- 麦克风按钮交互和好感度条模拟 ---
let isListening = false; let isListening = false;

View File

@@ -13,15 +13,29 @@ html, body {
} }
/* --- 视频背景 --- */ /* --- 视频背景 --- */
#bg-video { .video-container {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
z-index: -1; /* 将视频置于最底层 */ z-index: -1;
object-fit: cover; /* 默认填满整个屏幕裁剪JS会切换它 */ background-color: #1a1a1a;
background-color: #1a1a1a; /* 视频加载前的背景色 */ }
.bg-video {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0;
transition: opacity 1.5s ease-in-out; /* 交叉淡入淡出动画 */
}
.bg-video.active {
opacity: 1;
} }
/* --- 内容覆盖层 --- */ /* --- 内容覆盖层 --- */