|
|
<!-- 轮播组件外层容器,包含左右切换按钮 -->
|
|
|
<div class="phone-carousel-container">
|
|
|
<!-- 左切换按钮 -->
|
|
|
<button class="carousel-nav-btn carousel-prev-btn" aria-label="上一张">
|
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
|
<path d="M15 18L9 12L15 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
|
</svg>
|
|
|
</button>
|
|
|
|
|
|
<!-- 手机轮播组件 -->
|
|
|
<div class="phone-carousel-wrapper">
|
|
|
<style>
|
|
|
.phone-carousel-wrapper * {
|
|
|
margin: 0;
|
|
|
padding: 0;
|
|
|
box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 外层容器样式 - 包含左右切换按钮
|
|
|
*/
|
|
|
.phone-carousel-container {
|
|
|
position: relative;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
padding: 20px 80px; /* 左右留出按钮空间 */
|
|
|
min-height: 400px;
|
|
|
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 左右切换按钮样式
|
|
|
*/
|
|
|
.carousel-nav-btn {
|
|
|
position: absolute;
|
|
|
top: 50%;
|
|
|
transform: translateY(-50%);
|
|
|
width: 50px;
|
|
|
height: 50px;
|
|
|
border: none;
|
|
|
border-radius: 50%;
|
|
|
background: rgba(255, 255, 255, 0.9);
|
|
|
color: #333;
|
|
|
cursor: pointer;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
|
transition: all 0.3s ease;
|
|
|
z-index: 10;
|
|
|
}
|
|
|
|
|
|
.carousel-nav-btn:hover {
|
|
|
background: rgba(255, 255, 255, 1);
|
|
|
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
|
|
|
transform: translateY(-50%) scale(1.1);
|
|
|
}
|
|
|
|
|
|
.carousel-nav-btn:active {
|
|
|
transform: translateY(-50%) scale(0.95);
|
|
|
}
|
|
|
|
|
|
.carousel-prev-btn {
|
|
|
left: -52px;
|
|
|
}
|
|
|
|
|
|
.carousel-next-btn {
|
|
|
right: -52px;
|
|
|
}
|
|
|
|
|
|
.carousel-nav-btn svg {
|
|
|
width: 24px;
|
|
|
height: 24px;
|
|
|
transition: transform 0.2s ease;
|
|
|
}
|
|
|
|
|
|
.carousel-nav-btn:hover svg {
|
|
|
transform: scale(1.1);
|
|
|
}
|
|
|
|
|
|
.phone-carousel-wrapper {
|
|
|
display: flex;
|
|
|
justify-content: center;
|
|
|
align-items: center;
|
|
|
flex: 1;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 手机模型容器样式
|
|
|
*
|
|
|
*/
|
|
|
.phone-carousel-wrapper .phone-container {
|
|
|
position: relative;
|
|
|
width: 220px;
|
|
|
height: 440px; /* 调整为接近图片比例 306:617 ≈ 1:2 */
|
|
|
background-image: url('<?php echo get_template_directory_uri(); ?>/assets/images/phone-carousel-imgs/phone-bg.png');
|
|
|
background-size: contain;
|
|
|
background-repeat: no-repeat;
|
|
|
background-position: center;
|
|
|
display: flex;
|
|
|
justify-content: center;
|
|
|
align-items: center;
|
|
|
filter: drop-shadow(0 20px 40px rgba(0, 0, 0, 0.3));
|
|
|
animation: phoneFloat 3s ease-in-out infinite;
|
|
|
}
|
|
|
/**
|
|
|
* 轮播图容器样式
|
|
|
* 位于手机屏幕区域内,保持与phone-container相同的宽高比例 (1:2)
|
|
|
*/
|
|
|
.phone-carousel-wrapper .carousel-container {
|
|
|
position: absolute;
|
|
|
width: 180px; /* 调整为适合手机屏幕区域 */
|
|
|
height: 320px; /* 调整为适合手机屏幕区域 */
|
|
|
top: 50%;
|
|
|
left: 50%;
|
|
|
transform: translate(-50%, -50%);
|
|
|
overflow: visible;
|
|
|
cursor: grab; /* 添加拖拽光标 */
|
|
|
}
|
|
|
|
|
|
.phone-carousel-wrapper .carousel-container:active {
|
|
|
cursor: grabbing; /* 拖拽时的光标 */
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 轮播图包装器
|
|
|
*/
|
|
|
.phone-carousel-wrapper .carousel-wrapper {
|
|
|
position: relative;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
overflow: hidden;
|
|
|
border-radius: 25px;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 轮播图片样式
|
|
|
*/
|
|
|
.phone-carousel-wrapper .carousel-slide {
|
|
|
position: absolute;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
opacity: 0;
|
|
|
transition: opacity 1s ease-in-out;
|
|
|
}
|
|
|
|
|
|
.phone-carousel-wrapper .carousel-slide.active {
|
|
|
opacity: 1;
|
|
|
}
|
|
|
|
|
|
.phone-carousel-wrapper .carousel-slide img {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
object-fit: contain;
|
|
|
border-radius: 25px;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 动画效果
|
|
|
*/
|
|
|
@keyframes phoneFloat {
|
|
|
0%, 100% {
|
|
|
transform: translateY(0px);
|
|
|
}
|
|
|
50% {
|
|
|
transform: translateY(-10px);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.phone-carousel-wrapper .phone-container {
|
|
|
animation: phoneFloat 3s ease-in-out infinite;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 响应式设计
|
|
|
* 移动端也保持相同的1:2宽高比例
|
|
|
*/
|
|
|
@media (max-width: 768px) {
|
|
|
.phone-carousel-container {
|
|
|
padding: 20px 60px; /* 移动端减少左右间距 */
|
|
|
}
|
|
|
|
|
|
.carousel-nav-btn {
|
|
|
width: 40px;
|
|
|
height: 40px;
|
|
|
}
|
|
|
|
|
|
.carousel-nav-btn svg {
|
|
|
width: 20px;
|
|
|
height: 20px;
|
|
|
}
|
|
|
|
|
|
.carousel-prev-btn {
|
|
|
left: 10px;
|
|
|
}
|
|
|
|
|
|
.carousel-next-btn {
|
|
|
right: 10px;
|
|
|
}
|
|
|
|
|
|
.phone-carousel-wrapper .phone-container {
|
|
|
width: 200px;
|
|
|
height: 400px; /* 保持与桌面版相似的比例 */
|
|
|
}
|
|
|
|
|
|
.phone-carousel-wrapper .carousel-container {
|
|
|
width: 160px; /* 调整为适合移动端手机屏幕区域 */
|
|
|
height: 280px; /* 调整为适合移动端手机屏幕区域 */
|
|
|
}
|
|
|
}
|
|
|
</style>
|
|
|
<!-- 手机模型容器 -->
|
|
|
<div class="phone-container">
|
|
|
<!-- 轮播图容器 -->
|
|
|
<div class="carousel-container">
|
|
|
<div class="carousel-wrapper">
|
|
|
<!-- 轮播图片 -->
|
|
|
<div class="carousel-slide active">
|
|
|
<img src="<?php echo get_template_directory_uri(); ?>/assets/images/phone-carousel-imgs/phone-001.png" alt="手机展示图1">
|
|
|
</div>
|
|
|
<div class="carousel-slide">
|
|
|
<img src="<?php echo get_template_directory_uri(); ?>/assets/images/phone-carousel-imgs/phone-002.png" alt="手机展示图2">
|
|
|
</div>
|
|
|
<div class="carousel-slide">
|
|
|
<img src="<?php echo get_template_directory_uri(); ?>/assets/images/phone-carousel-imgs/phone-003.png" alt="手机展示图3">
|
|
|
</div>
|
|
|
<div class="carousel-slide">
|
|
|
<img src="<?php echo get_template_directory_uri(); ?>/assets/images/phone-carousel-imgs/phone-004.png" alt="手机展示图4">
|
|
|
</div>
|
|
|
<div class="carousel-slide">
|
|
|
<img src="<?php echo get_template_directory_uri(); ?>/assets/images/phone-carousel-imgs/phone-005.png" alt="手机展示图5">
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<script>
|
|
|
/**
|
|
|
* 轮播图拖拽切换功能
|
|
|
* 支持触摸和鼠标拖拽操作
|
|
|
*/
|
|
|
class PhoneCarousel {
|
|
|
constructor() {
|
|
|
this.slides = document.querySelectorAll('.carousel-slide');
|
|
|
this.container = document.querySelector('.carousel-container');
|
|
|
this.currentSlide = 0;
|
|
|
this.slideInterval = null;
|
|
|
this.autoPlayDelay = 1500; // 1.5秒自动切换
|
|
|
|
|
|
// 拖拽相关属性
|
|
|
this.isDragging = false;
|
|
|
this.startX = 0;
|
|
|
this.currentX = 0;
|
|
|
this.threshold = 50; // 拖拽阈值,超过此距离才切换
|
|
|
|
|
|
// 性能优化属性
|
|
|
this.isDestroyed = false;
|
|
|
this.boundHandlers = {};
|
|
|
this.resizeTimeout = null;
|
|
|
|
|
|
this.init();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 初始化轮播图
|
|
|
*/
|
|
|
init() {
|
|
|
if (this.isDestroyed) return;
|
|
|
|
|
|
// 检查必要元素是否存在
|
|
|
if (!this.container || this.slides.length === 0) {
|
|
|
console.warn('PhoneCarousel: 必要元素未找到');
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
this.bindEvents();
|
|
|
this.bindNavButtons(); // 绑定导航按钮事件
|
|
|
this.startAutoPlay();
|
|
|
|
|
|
// 添加窗口大小变化监听(防抖处理)
|
|
|
this.boundHandlers.resize = this.debounce(() => {
|
|
|
if (!this.isDestroyed) {
|
|
|
this.handleResize();
|
|
|
}
|
|
|
}, 250);
|
|
|
window.addEventListener('resize', this.boundHandlers.resize);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 防抖函数
|
|
|
*/
|
|
|
debounce(func, wait) {
|
|
|
return (...args) => {
|
|
|
clearTimeout(this.resizeTimeout);
|
|
|
this.resizeTimeout = setTimeout(() => func.apply(this, args), wait);
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 处理窗口大小变化
|
|
|
*/
|
|
|
handleResize() {
|
|
|
// 重新计算容器尺寸和位置
|
|
|
if (this.container) {
|
|
|
this.resetAutoPlay();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 绑定导航按钮事件
|
|
|
*/
|
|
|
bindNavButtons() {
|
|
|
const prevBtn = document.querySelector('.carousel-prev-btn');
|
|
|
const nextBtn = document.querySelector('.carousel-next-btn');
|
|
|
|
|
|
if (prevBtn) {
|
|
|
prevBtn.addEventListener('click', () => {
|
|
|
this.prevSlide();
|
|
|
this.resetAutoPlay(); // 重置自动播放
|
|
|
});
|
|
|
}
|
|
|
|
|
|
if (nextBtn) {
|
|
|
nextBtn.addEventListener('click', () => {
|
|
|
this.nextSlide();
|
|
|
this.resetAutoPlay(); // 重置自动播放
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 绑定事件监听器
|
|
|
*/
|
|
|
bindEvents() {
|
|
|
if (this.isDestroyed || !this.container) return;
|
|
|
|
|
|
// 使用绑定的处理函数,便于后续清理
|
|
|
this.boundHandlers.touchStart = (e) => this.handleStart(e);
|
|
|
this.boundHandlers.touchMove = (e) => this.handleMove(e);
|
|
|
this.boundHandlers.touchEnd = (e) => this.handleEnd(e);
|
|
|
this.boundHandlers.mouseDown = (e) => this.handleStart(e);
|
|
|
this.boundHandlers.mouseMove = (e) => this.handleMove(e);
|
|
|
this.boundHandlers.mouseUp = (e) => this.handleEnd(e);
|
|
|
this.boundHandlers.mouseLeave = (e) => this.handleEnd(e);
|
|
|
this.boundHandlers.dragStart = (e) => e.preventDefault();
|
|
|
this.boundHandlers.mouseEnter = () => this.stopAutoPlay();
|
|
|
this.boundHandlers.mouseLeaveContainer = () => {
|
|
|
if (!this.isDragging) {
|
|
|
this.startAutoPlay();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 触摸事件(移动端)
|
|
|
this.container.addEventListener('touchstart', this.boundHandlers.touchStart, { passive: false });
|
|
|
this.container.addEventListener('touchmove', this.boundHandlers.touchMove, { passive: false });
|
|
|
this.container.addEventListener('touchend', this.boundHandlers.touchEnd, { passive: false });
|
|
|
|
|
|
// 鼠标事件(桌面端)
|
|
|
this.container.addEventListener('mousedown', this.boundHandlers.mouseDown);
|
|
|
this.container.addEventListener('mousemove', this.boundHandlers.mouseMove);
|
|
|
this.container.addEventListener('mouseup', this.boundHandlers.mouseUp);
|
|
|
this.container.addEventListener('mouseleave', this.boundHandlers.mouseLeave);
|
|
|
|
|
|
// 防止图片拖拽
|
|
|
this.container.addEventListener('dragstart', this.boundHandlers.dragStart);
|
|
|
|
|
|
// 鼠标悬停暂停自动播放
|
|
|
this.container.addEventListener('mouseenter', this.boundHandlers.mouseEnter);
|
|
|
this.container.addEventListener('mouseleave', this.boundHandlers.mouseLeaveContainer);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 清理事件监听器
|
|
|
*/
|
|
|
unbindEvents() {
|
|
|
if (!this.container || !this.boundHandlers) return;
|
|
|
|
|
|
// 移除所有事件监听器
|
|
|
this.container.removeEventListener('touchstart', this.boundHandlers.touchStart);
|
|
|
this.container.removeEventListener('touchmove', this.boundHandlers.touchMove);
|
|
|
this.container.removeEventListener('touchend', this.boundHandlers.touchEnd);
|
|
|
this.container.removeEventListener('mousedown', this.boundHandlers.mouseDown);
|
|
|
this.container.removeEventListener('mousemove', this.boundHandlers.mouseMove);
|
|
|
this.container.removeEventListener('mouseup', this.boundHandlers.mouseUp);
|
|
|
this.container.removeEventListener('mouseleave', this.boundHandlers.mouseLeave);
|
|
|
this.container.removeEventListener('dragstart', this.boundHandlers.dragStart);
|
|
|
this.container.removeEventListener('mouseenter', this.boundHandlers.mouseEnter);
|
|
|
this.container.removeEventListener('mouseleave', this.boundHandlers.mouseLeaveContainer);
|
|
|
|
|
|
if (this.boundHandlers.resize) {
|
|
|
window.removeEventListener('resize', this.boundHandlers.resize);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 处理拖拽开始事件
|
|
|
* @param {Event} e - 事件对象
|
|
|
*/
|
|
|
handleStart(e) {
|
|
|
this.isDragging = true;
|
|
|
this.startX = this.getClientX(e);
|
|
|
this.currentX = this.startX;
|
|
|
this.stopAutoPlay();
|
|
|
|
|
|
// 添加拖拽样式
|
|
|
this.container.style.cursor = 'grabbing';
|
|
|
this.container.style.userSelect = 'none';
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 处理拖拽移动事件
|
|
|
* @param {Event} e - 事件对象
|
|
|
*/
|
|
|
handleMove(e) {
|
|
|
if (!this.isDragging) return;
|
|
|
|
|
|
e.preventDefault();
|
|
|
this.currentX = this.getClientX(e);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 处理拖拽结束事件
|
|
|
* @param {Event} e - 事件对象
|
|
|
*/
|
|
|
handleEnd(e) {
|
|
|
if (!this.isDragging) return;
|
|
|
|
|
|
this.isDragging = false;
|
|
|
const deltaX = this.currentX - this.startX;
|
|
|
|
|
|
// 移除拖拽样式
|
|
|
this.container.style.cursor = 'grab';
|
|
|
this.container.style.userSelect = '';
|
|
|
|
|
|
// 根据拖拽距离判断是否切换
|
|
|
if (Math.abs(deltaX) > this.threshold) {
|
|
|
if (deltaX > 0) {
|
|
|
// 向右拖拽,显示上一张
|
|
|
this.prevSlide();
|
|
|
} else {
|
|
|
// 向左拖拽,显示下一张
|
|
|
this.nextSlide();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 重新开始自动播放
|
|
|
this.startAutoPlay();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取客户端X坐标
|
|
|
* @param {Event} e - 事件对象
|
|
|
* @returns {number} X坐标
|
|
|
*/
|
|
|
getClientX(e) {
|
|
|
return e.type.includes('touch') ? e.touches[0]?.clientX || e.changedTouches[0]?.clientX : e.clientX;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 切换到指定幻灯片
|
|
|
* @param {number} slideIndex - 幻灯片索引
|
|
|
*/
|
|
|
goToSlide(slideIndex) {
|
|
|
// 移除当前活动状态
|
|
|
this.slides[this.currentSlide].classList.remove('active');
|
|
|
|
|
|
// 设置新的活动状态
|
|
|
this.currentSlide = slideIndex;
|
|
|
this.slides[this.currentSlide].classList.add('active');
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 切换到上一张幻灯片
|
|
|
*/
|
|
|
prevSlide() {
|
|
|
const prevIndex = this.currentSlide === 0 ? this.slides.length - 1 : this.currentSlide - 1;
|
|
|
this.goToSlide(prevIndex);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 切换到下一张幻灯片
|
|
|
*/
|
|
|
nextSlide() {
|
|
|
const nextIndex = (this.currentSlide + 1) % this.slides.length;
|
|
|
this.goToSlide(nextIndex);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 开始自动播放
|
|
|
*/
|
|
|
startAutoPlay() {
|
|
|
this.slideInterval = setInterval(() => {
|
|
|
this.nextSlide();
|
|
|
}, this.autoPlayDelay);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 停止自动播放
|
|
|
*/
|
|
|
stopAutoPlay() {
|
|
|
if (this.slideInterval) {
|
|
|
clearInterval(this.slideInterval);
|
|
|
this.slideInterval = null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 重置自动播放
|
|
|
*/
|
|
|
resetAutoPlay() {
|
|
|
if (this.isDestroyed) return;
|
|
|
this.stopAutoPlay();
|
|
|
this.startAutoPlay();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 销毁轮播图实例
|
|
|
*/
|
|
|
destroy() {
|
|
|
this.isDestroyed = true;
|
|
|
this.stopAutoPlay();
|
|
|
this.unbindEvents();
|
|
|
|
|
|
// 清理定时器
|
|
|
if (this.resizeTimeout) {
|
|
|
clearTimeout(this.resizeTimeout);
|
|
|
this.resizeTimeout = null;
|
|
|
}
|
|
|
|
|
|
// 清理引用
|
|
|
this.slides = null;
|
|
|
this.container = null;
|
|
|
this.boundHandlers = null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 页面加载完成后初始化轮播图
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
|
// 检查是否已经初始化过(避免重复初始化)
|
|
|
if (window.phoneCarouselInstance) {
|
|
|
window.phoneCarouselInstance.destroy();
|
|
|
}
|
|
|
|
|
|
// 直接初始化轮播图
|
|
|
window.phoneCarouselInstance = new PhoneCarousel();
|
|
|
});
|
|
|
|
|
|
// 页面卸载时清理资源
|
|
|
window.addEventListener('beforeunload', () => {
|
|
|
if (window.phoneCarouselInstance) {
|
|
|
window.phoneCarouselInstance.destroy();
|
|
|
}
|
|
|
});
|
|
|
</script>
|
|
|
</div>
|
|
|
|
|
|
<!-- 右切换按钮 -->
|
|
|
<button class="carousel-nav-btn carousel-next-btn" aria-label="下一张">
|
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
|
<path d="M9 18L15 12L9 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
|
</svg>
|
|
|
</button>
|
|
|
</div> |