You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

324 lines
9.6 KiB

/**
* 视频横幅功能脚本
* 处理视频播放、视频背景和GSAP动画
*/
// 全局变量
let videoBannerInitialized = false;
// 视频模态框功能
function openVideoModal(element) {
const container = element.closest('.video-banner-container');
if (!container) return;
const videoUrl = container.getAttribute('data-video-url');
const videoTitle = container.getAttribute('data-video-title') || '视频播放';
if (!videoUrl) return;
const modal = document.getElementById('video-modal');
const modalVideo = document.getElementById('modal-video');
const modalTitle = document.getElementById('video-modal-title');
if (modal && modalVideo && modalTitle) {
modalTitle.textContent = videoTitle;
modalVideo.src = videoUrl;
modal.style.display = 'block';
// 添加动画效果
if (typeof gsap !== 'undefined') {
gsap.fromTo(modal.querySelector('.video-modal-content'),
{ scale: 0.8, opacity: 0 },
{ scale: 1, opacity: 1, duration: 0.3, ease: "back.out(1.7)" }
);
}
// 阻止背景滚动
document.body.style.overflow = 'hidden';
}
}
function closeVideoModal() {
const modal = document.getElementById('video-modal');
const modalVideo = document.getElementById('modal-video');
if (modal && modalVideo) {
// 添加关闭动画
if (typeof gsap !== 'undefined') {
gsap.to(modal.querySelector('.video-modal-content'), {
scale: 0.8,
opacity: 0,
duration: 0.2,
ease: "power2.in",
onComplete: () => {
modal.style.display = 'none';
modalVideo.src = '';
document.body.style.overflow = '';
}
});
} else {
modal.style.display = 'none';
modalVideo.src = '';
document.body.style.overflow = '';
}
}
}
// 视频背景管理
class VideoBannerManager {
constructor() {
this.containers = [];
this.init();
}
init() {
this.findContainers();
this.setupEventListeners();
this.initializeVideos();
this.setupAnimations();
}
findContainers() {
this.containers = Array.from(document.querySelectorAll('.video-banner-container'));
}
setupEventListeners() {
// 窗口调整大小时重新初始化
window.addEventListener('resize', this.debounce(() => {
this.handleResize();
}, 250));
// 模态框点击外部关闭
const modal = document.getElementById('video-modal');
if (modal) {
modal.addEventListener('click', (e) => {
if (e.target === modal) {
closeVideoModal();
}
});
}
// ESC键关闭模态框
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
closeVideoModal();
}
});
}
initializeVideos() {
this.containers.forEach(container => {
const video = container.querySelector('.video-background');
if (video) {
this.setupVideo(video, container);
}
});
}
setupVideo(video, container) {
// 设置视频属性
video.muted = true;
video.loop = true;
video.playsInline = true;
video.autoplay = true;
// 监听视频事件
video.addEventListener('loadeddata', () => {
this.onVideoLoaded(video, container);
});
video.addEventListener('canplay', () => {
this.playVideo(video);
});
video.addEventListener('error', (e) => {
console.error('视频加载失败:', e);
this.handleVideoError(video, container);
});
// 尝试播放视频
this.playVideo(video);
}
onVideoLoaded(video, container) {
// 视频加载完成后的处理
video.style.opacity = '1';
// 添加淡入动画
if (typeof gsap !== 'undefined') {
gsap.fromTo(video,
{ opacity: 0 },
{ opacity: 1, duration: 1, ease: "power2.out" }
);
}
}
playVideo(video) {
const playPromise = video.play();
if (playPromise !== undefined) {
playPromise.then(() => {
// 自动播放成功
}).catch(error => {
// 自动播放失败,通常是由于浏览器政策
this.handleAutoplayFailure(video);
});
}
}
handleAutoplayFailure(video) {
// 创建播放按钮
const container = video.closest('.video-banner-container');
if (container && !container.querySelector('.video-play-trigger')) {
const playButton = document.createElement('div');
playButton.className = 'video-play-trigger';
playButton.innerHTML = `
<div class="play-icon-overlay">
<svg width="80" height="80" viewBox="0 0 80 80" fill="none">
<circle cx="40" cy="40" r="40" fill="rgba(255,255,255,0.9)"/>
<polygon points="32,25 32,55 55,40" fill="#333"/>
</svg>
</div>
`;
playButton.addEventListener('click', () => {
video.play();
playButton.remove();
});
container.appendChild(playButton);
}
}
handleVideoError(video, container) {
// 视频加载错误处理
const errorDiv = document.createElement('div');
errorDiv.className = 'video-error-message';
errorDiv.textContent = '视频加载失败';
container.appendChild(errorDiv);
}
handleResize() {
// 处理窗口大小变化
this.containers.forEach(container => {
const video = container.querySelector('.video-background');
if (video) {
this.adjustVideoSize(video, container);
}
});
}
adjustVideoSize(video, container) {
// 调整视频尺寸以适应容器
const containerRect = container.getBoundingClientRect();
const videoRect = video.getBoundingClientRect();
const containerRatio = containerRect.width / containerRect.height;
const videoRatio = video.videoWidth / video.videoHeight;
if (containerRatio > videoRatio) {
video.style.width = '100%';
video.style.height = 'auto';
} else {
video.style.width = 'auto';
video.style.height = '100%';
}
}
setupAnimations() {
if (typeof gsap === 'undefined') return;
// 等待GSAP兼容性就绪
if (!document.body.classList.contains('gsap-ready')) {
document.addEventListener('gsapCompatibilityReady', () => {
this.setupAnimations();
});
return;
}
this.containers.forEach(container => {
this.animateContainer(container);
});
}
animateContainer(container) {
const content = container.querySelector('.video-banner-content');
const title = container.querySelector('.video-banner-title');
const subtitle = container.querySelector('.video-banner-subtitle');
const description = container.querySelector('.video-banner-description');
const playButton = container.querySelector('.video-banner-play-button');
// 创建时间线动画
const tl = gsap.timeline({ delay: 0.5 });
if (subtitle) {
tl.fromTo(subtitle,
{ y: 30, opacity: 0 },
{ y: 0, opacity: 1, duration: 0.8, ease: "power2.out" }
);
}
if (title) {
tl.fromTo(title,
{ y: 50, opacity: 0 },
{ y: 0, opacity: 1, duration: 1, ease: "power2.out" },
"-=0.6"
);
}
if (description) {
tl.fromTo(description,
{ y: 30, opacity: 0 },
{ y: 0, opacity: 1, duration: 0.8, ease: "power2.out" },
"-=0.4"
);
}
if (playButton) {
tl.fromTo(playButton,
{ scale: 0, opacity: 0 },
{ scale: 1, opacity: 1, duration: 0.6, ease: "back.out(1.7)" },
"-=0.2"
);
}
}
// 工具函数:防抖
debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
}
// 初始化
document.addEventListener('DOMContentLoaded', function() {
if (!videoBannerInitialized) {
new VideoBannerManager();
videoBannerInitialized = true;
}
});
// 如果页面已经加载完成
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
if (!videoBannerInitialized) {
new VideoBannerManager();
videoBannerInitialized = true;
}
});
} else {
if (!videoBannerInitialized) {
new VideoBannerManager();
videoBannerInitialized = true;
}
}