|
|
<?php
|
|
|
/**
|
|
|
* 证书轮播区块模板
|
|
|
* 一行显示5个证书,每次切换一个
|
|
|
*/
|
|
|
|
|
|
// 检查是否显示证书轮播
|
|
|
if (!get_certificates_carousel_show()) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 获取配置数据
|
|
|
$title = get_certificates_carousel_title();
|
|
|
$subtitle = get_certificates_carousel_subtitle();
|
|
|
$autoplay = get_certificates_carousel_autoplay();
|
|
|
$delay = get_certificates_carousel_delay();
|
|
|
$images = get_certificates_carousel_images();
|
|
|
|
|
|
// 如果没有图片,则不显示
|
|
|
if (empty($images)) {
|
|
|
return;
|
|
|
}
|
|
|
?>
|
|
|
|
|
|
<section class="certificates-carousel-section" id="certificates-carousel">
|
|
|
<div class="certificates-carousel-container">
|
|
|
<div class="certificates-carousel-header">
|
|
|
<h2 class="certificates-carousel-title">奖项与证书</h2>
|
|
|
</div>
|
|
|
<!-- 证书轮播容器 -->
|
|
|
<div class="certificates-carousel" id="certificatesCarousel">
|
|
|
<div class="carousel-track" id="carouselTrack">
|
|
|
<?php foreach ($images as $index => $image): ?>
|
|
|
<div class="slide" data-slide="<?php echo $index; ?>">
|
|
|
<img src="<?php echo esc_url($image['url']); ?>"
|
|
|
alt="<?php echo esc_attr($image['alt']); ?>"
|
|
|
loading="<?php echo $index < 5 ? 'eager' : 'lazy'; ?>">
|
|
|
<h3 class="slide-title"><?php echo esc_html($image['title']); ?></h3>
|
|
|
</div>
|
|
|
<?php endforeach; ?>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</section>
|
|
|
|
|
|
<style>
|
|
|
.certificates-carousel-section {
|
|
|
padding: 80px 0;
|
|
|
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
|
|
position: relative;
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel-section::before {
|
|
|
content: '';
|
|
|
position: absolute;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
right: 0;
|
|
|
bottom: 0;
|
|
|
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grain" width="100" height="100" patternUnits="userSpaceOnUse"><circle cx="50" cy="50" r="1" fill="%23000" opacity="0.02"/></pattern></defs><rect width="100" height="100" fill="url(%23grain)"/></svg>') repeat;
|
|
|
pointer-events: none;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel-container {
|
|
|
max-width: 1400px;
|
|
|
margin: 0 auto;
|
|
|
padding: 0 20px;
|
|
|
position: relative;
|
|
|
z-index: 1;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel-header {
|
|
|
text-align: center;
|
|
|
margin-bottom: 60px;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel-title {
|
|
|
font-size: 2.5rem;
|
|
|
font-weight: 700;
|
|
|
color: #2c3e50;
|
|
|
margin-bottom: 15px;
|
|
|
position: relative;
|
|
|
display: inline-block;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel-title::after {
|
|
|
content: '';
|
|
|
position: absolute;
|
|
|
bottom: -10px;
|
|
|
left: 50%;
|
|
|
transform: translateX(-50%);
|
|
|
width: 60px;
|
|
|
height: 4px;
|
|
|
background: linear-gradient(90deg, #3498db, #2980b9);
|
|
|
border-radius: 2px;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel-subtitle {
|
|
|
font-size: 1.2rem;
|
|
|
color: #7f8c8d;
|
|
|
font-weight: 400;
|
|
|
margin: 0;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel {
|
|
|
position: relative;
|
|
|
border-radius: 20px;
|
|
|
overflow: hidden;
|
|
|
padding: 40px;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel .carousel-track {
|
|
|
display: flex;
|
|
|
gap: 20px;
|
|
|
transition: transform 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
|
|
width: 100%;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel .slide {
|
|
|
flex: 0 0 calc((100% - 80px) / 5);
|
|
|
min-width: calc((100% - 80px) / 5);
|
|
|
text-align: center;
|
|
|
background: #fff;
|
|
|
border-radius: 12px;
|
|
|
padding: 20px;
|
|
|
box-shadow: 0 5px 15px rgba(0,0,0,0.08);
|
|
|
opacity: 1;
|
|
|
transition: all 0.3s ease;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel .slide:hover {
|
|
|
transform: translateY(-5px);
|
|
|
box-shadow: 0 10px 25px rgba(0,0,0,0.15);
|
|
|
}
|
|
|
|
|
|
.certificates-carousel .slide img {
|
|
|
width: 100%;
|
|
|
max-height: 200px;
|
|
|
object-fit: contain;
|
|
|
aspect-ratio: 141/200;
|
|
|
border-radius: 8px;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel .slide img:hover {
|
|
|
transform: scale(1.05);
|
|
|
}
|
|
|
|
|
|
.certificates-carousel .slide-title {
|
|
|
font-size: 0.9rem;
|
|
|
font-weight: 600;
|
|
|
color: #2c3e50;
|
|
|
margin: 15px 0 0;
|
|
|
line-height: 1.4;
|
|
|
}
|
|
|
|
|
|
/* 导航容器样式 */
|
|
|
.carousel-navigation {
|
|
|
display: flex;
|
|
|
justify-content: flex-start;
|
|
|
align-items: center;
|
|
|
gap: 20px;
|
|
|
margin-top: 30px;
|
|
|
position: relative;
|
|
|
}
|
|
|
|
|
|
.carousel-nav {
|
|
|
background: rgba(255,255,255,0.9);
|
|
|
border: none;
|
|
|
width: 50px;
|
|
|
height: 50px;
|
|
|
border-radius: 50%;
|
|
|
font-size: 24px;
|
|
|
cursor: pointer;
|
|
|
z-index: 10;
|
|
|
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
|
|
|
transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
|
|
color: #333;
|
|
|
font-weight: bold;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
|
|
|
.carousel-nav:hover {
|
|
|
background: rgba(52, 152, 219, 0.95);
|
|
|
color: #fff;
|
|
|
transform: scale(1.15);
|
|
|
box-shadow: 0 6px 25px rgba(52, 152, 219, 0.3);
|
|
|
}
|
|
|
|
|
|
/* 响应式设计 */
|
|
|
@media (max-width: 1200px) {
|
|
|
.certificates-carousel .slide {
|
|
|
flex: 0 0 calc((100% - 60px) / 4);
|
|
|
min-width: calc((100% - 60px) / 4);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
.certificates-carousel-section {
|
|
|
padding: 60px 0;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel-container {
|
|
|
padding: 0 15px;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel-title {
|
|
|
font-size: 2rem;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel-subtitle {
|
|
|
font-size: 1.1rem;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel {
|
|
|
padding: 30px 20px;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel .slide {
|
|
|
flex: 0 0 calc((100% - 15px) / 2);
|
|
|
min-width: calc((100% - 15px) / 2);
|
|
|
padding: 15px;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel .slide img {
|
|
|
max-height: 160px;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel .carousel-track {
|
|
|
gap: 15px;
|
|
|
}
|
|
|
|
|
|
.carousel-navigation {
|
|
|
margin-top: 25px;
|
|
|
gap: 15px;
|
|
|
}
|
|
|
|
|
|
.carousel-nav {
|
|
|
width: 45px;
|
|
|
height: 45px;
|
|
|
font-size: 20px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@media (max-width: 480px) {
|
|
|
.certificates-carousel-title {
|
|
|
font-size: 1.8rem;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel {
|
|
|
padding: 25px 15px;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel .slide {
|
|
|
flex: 0 0 100%;
|
|
|
min-width: 100%;
|
|
|
}
|
|
|
|
|
|
.certificates-carousel .slide img {
|
|
|
max-height: 140px;
|
|
|
}
|
|
|
|
|
|
.carousel-navigation {
|
|
|
margin-top: 20px;
|
|
|
gap: 12px;
|
|
|
}
|
|
|
|
|
|
.carousel-nav {
|
|
|
width: 40px;
|
|
|
height: 40px;
|
|
|
font-size: 18px;
|
|
|
}
|
|
|
}
|
|
|
</style>
|
|
|
|
|
|
<?php
|
|
|
// 确保GSAP库被加载
|
|
|
if (!wp_script_is('gsap', 'enqueued')) {
|
|
|
$theme_url = get_template_directory_uri();
|
|
|
wp_enqueue_script('gsap', $theme_url . '/assets/js/gsap.min.js', array('jquery'), '3.12.2', true);
|
|
|
}
|
|
|
?>
|
|
|
|
|
|
<script>
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
const carousel = document.getElementById('certificatesCarousel');
|
|
|
const track = document.getElementById('carouselTrack');
|
|
|
if (!carousel || !track) return;
|
|
|
|
|
|
const slides = track.querySelectorAll('.slide');
|
|
|
const totalSlides = slides.length;
|
|
|
let currentIndex = 0;
|
|
|
|
|
|
// 获取自定义器设置
|
|
|
const autoplay = <?php echo get_certificates_carousel_autoplay() ? 'true' : 'false'; ?>;
|
|
|
const delay = <?php echo get_certificates_carousel_delay(); ?>;
|
|
|
|
|
|
// 计算每次显示的幻灯片数量
|
|
|
function getSlidesPerView() {
|
|
|
const width = window.innerWidth;
|
|
|
if (width <= 480) return 1;
|
|
|
if (width <= 768) return 2;
|
|
|
if (width <= 1200) return 4;
|
|
|
return 5;
|
|
|
}
|
|
|
|
|
|
// 获取当前gap间距
|
|
|
function getCurrentGap() {
|
|
|
const width = window.innerWidth;
|
|
|
if (width <= 768) return 15;
|
|
|
return 20;
|
|
|
}
|
|
|
|
|
|
// 更新轮播位置
|
|
|
function updateCarousel() {
|
|
|
const slidesPerView = getSlidesPerView();
|
|
|
const gap = getCurrentGap();
|
|
|
const containerWidth = carousel.offsetWidth - 80; // 减去padding
|
|
|
const slideWidth = (containerWidth - (gap * (slidesPerView - 1))) / slidesPerView;
|
|
|
const translateX = -(currentIndex * (slideWidth + gap));
|
|
|
|
|
|
// 使用GSAP实现平滑动画
|
|
|
if (typeof gsap !== 'undefined') {
|
|
|
gsap.to(track, {
|
|
|
x: translateX,
|
|
|
duration: 0.8,
|
|
|
ease: "power2.out"
|
|
|
});
|
|
|
} else {
|
|
|
// 降级到CSS过渡
|
|
|
track.style.transform = `translateX(${translateX}px)`;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 下一张
|
|
|
function nextSlide() {
|
|
|
const slidesPerView = getSlidesPerView();
|
|
|
const maxIndex = Math.max(0, totalSlides - slidesPerView);
|
|
|
if (currentIndex >= maxIndex) {
|
|
|
currentIndex = 0; // 循环到开始
|
|
|
} else {
|
|
|
currentIndex++;
|
|
|
}
|
|
|
updateCarousel();
|
|
|
updateNavigationState();
|
|
|
}
|
|
|
|
|
|
// 上一张
|
|
|
function prevSlide() {
|
|
|
const slidesPerView = getSlidesPerView();
|
|
|
const maxIndex = Math.max(0, totalSlides - slidesPerView);
|
|
|
if (currentIndex <= 0) {
|
|
|
currentIndex = maxIndex; // 循环到结束
|
|
|
} else {
|
|
|
currentIndex--;
|
|
|
}
|
|
|
updateCarousel();
|
|
|
updateNavigationState();
|
|
|
}
|
|
|
|
|
|
// 更新导航按钮状态
|
|
|
function updateNavigationState() {
|
|
|
const slidesPerView = getSlidesPerView();
|
|
|
const maxIndex = Math.max(0, totalSlides - slidesPerView);
|
|
|
|
|
|
// 如果幻灯片数量少于或等于显示数量,隐藏导航
|
|
|
if (totalSlides <= slidesPerView) {
|
|
|
navContainer.style.display = 'none';
|
|
|
} else {
|
|
|
navContainer.style.display = 'flex';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 创建导航容器
|
|
|
const navContainer = document.createElement('div');
|
|
|
navContainer.className = 'carousel-navigation';
|
|
|
navContainer.style.cssText = 'display: flex; justify-content: flex-start; align-items: center; gap: 20px; margin-top: 30px; position: relative;';
|
|
|
|
|
|
// 创建导航按钮
|
|
|
const prevBtn = document.createElement('button');
|
|
|
prevBtn.innerHTML = '‹';
|
|
|
prevBtn.className = 'carousel-nav carousel-prev';
|
|
|
prevBtn.style.cssText = 'background: rgba(255,255,255,0.9); border: none; width: 50px; height: 50px; border-radius: 50%; font-size: 24px; cursor: pointer; z-index: 10; box-shadow: 0 4px 15px rgba(0,0,0,0.1); transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); color: #333; font-weight: bold;';
|
|
|
prevBtn.addEventListener('click', prevSlide);
|
|
|
|
|
|
const nextBtn = document.createElement('button');
|
|
|
nextBtn.innerHTML = '›';
|
|
|
nextBtn.className = 'carousel-nav carousel-next';
|
|
|
nextBtn.style.cssText = 'background: rgba(255,255,255,0.9); border: none; width: 50px; height: 50px; border-radius: 50%; font-size: 24px; cursor: pointer; z-index: 10; box-shadow: 0 4px 15px rgba(0,0,0,0.1); transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); color: #333; font-weight: bold;';
|
|
|
nextBtn.addEventListener('click', nextSlide);
|
|
|
|
|
|
// 将按钮添加到导航容器
|
|
|
navContainer.appendChild(prevBtn);
|
|
|
navContainer.appendChild(nextBtn);
|
|
|
|
|
|
// 将导航容器添加到轮播容器
|
|
|
carousel.appendChild(navContainer);
|
|
|
|
|
|
// 按钮悬停效果 - 使用GSAP
|
|
|
[prevBtn, nextBtn].forEach(btn => {
|
|
|
btn.addEventListener('mouseenter', () => {
|
|
|
if (typeof gsap !== 'undefined') {
|
|
|
gsap.to(btn, {
|
|
|
backgroundColor: 'rgba(52, 152, 219, 0.95)',
|
|
|
color: '#fff',
|
|
|
scale: 1.15,
|
|
|
boxShadow: '0 4px 20px rgba(52, 152, 219, 0.3)',
|
|
|
duration: 0.3,
|
|
|
ease: "power2.out"
|
|
|
});
|
|
|
} else {
|
|
|
btn.style.background = 'rgba(52, 152, 219, 0.95)';
|
|
|
btn.style.color = '#fff';
|
|
|
btn.style.transform = 'scale(1.15)';
|
|
|
btn.style.boxShadow = '0 4px 20px rgba(52, 152, 219, 0.3)';
|
|
|
}
|
|
|
});
|
|
|
btn.addEventListener('mouseleave', () => {
|
|
|
if (typeof gsap !== 'undefined') {
|
|
|
gsap.to(btn, {
|
|
|
backgroundColor: 'rgba(255,255,255,0.9)',
|
|
|
color: '#333',
|
|
|
scale: 1,
|
|
|
boxShadow: '0 2px 10px rgba(0,0,0,0.1)',
|
|
|
duration: 0.3,
|
|
|
ease: "power2.out"
|
|
|
});
|
|
|
} else {
|
|
|
btn.style.background = 'rgba(255,255,255,0.9)';
|
|
|
btn.style.color = '#333';
|
|
|
btn.style.transform = 'scale(1)';
|
|
|
btn.style.boxShadow = '0 4px 15px rgba(0,0,0,0.1)';
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
|
|
|
// 自动播放
|
|
|
let autoplayInterval;
|
|
|
if (autoplay) {
|
|
|
autoplayInterval = setInterval(nextSlide, delay);
|
|
|
|
|
|
// 鼠标悬停暂停
|
|
|
carousel.addEventListener('mouseenter', () => {
|
|
|
if (autoplayInterval) {
|
|
|
clearInterval(autoplayInterval);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
carousel.addEventListener('mouseleave', () => {
|
|
|
if (autoplay) {
|
|
|
autoplayInterval = setInterval(nextSlide, delay);
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
// 响应式更新
|
|
|
window.addEventListener('resize', () => {
|
|
|
updateCarousel();
|
|
|
updateNavigationState();
|
|
|
});
|
|
|
|
|
|
// 初始化GSAP动画效果
|
|
|
function initGSAPEffects() {
|
|
|
if (typeof gsap !== 'undefined') {
|
|
|
// 证书卡片悬停动画
|
|
|
slides.forEach(slide => {
|
|
|
const img = slide.querySelector('img');
|
|
|
if (img) {
|
|
|
slide.addEventListener('mouseenter', () => {
|
|
|
gsap.to(img, {
|
|
|
scale: 1.05,
|
|
|
duration: 0.3,
|
|
|
ease: "power2.out"
|
|
|
});
|
|
|
gsap.to(slide, {
|
|
|
y: -5,
|
|
|
boxShadow: '0 10px 25px rgba(0,0,0,0.15)',
|
|
|
duration: 0.3,
|
|
|
ease: "power2.out"
|
|
|
});
|
|
|
});
|
|
|
|
|
|
slide.addEventListener('mouseleave', () => {
|
|
|
gsap.to(img, {
|
|
|
scale: 1,
|
|
|
duration: 0.3,
|
|
|
ease: "power2.out"
|
|
|
});
|
|
|
gsap.to(slide, {
|
|
|
y: 0,
|
|
|
boxShadow: '0 4px 15px rgba(0,0,0,0.1)',
|
|
|
duration: 0.3,
|
|
|
ease: "power2.out"
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 初始加载动画
|
|
|
gsap.fromTo(slides, {
|
|
|
opacity: 0,
|
|
|
y: 30
|
|
|
}, {
|
|
|
opacity: 1,
|
|
|
y: 0,
|
|
|
duration: 0.6,
|
|
|
stagger: 0.1,
|
|
|
ease: "power2.out",
|
|
|
delay: 0.2
|
|
|
});
|
|
|
|
|
|
// 标题动画
|
|
|
const title = document.querySelector('.certificates-carousel-title');
|
|
|
const subtitle = document.querySelector('.certificates-carousel-subtitle');
|
|
|
if (title) {
|
|
|
gsap.fromTo(title, {
|
|
|
opacity: 0,
|
|
|
y: -20
|
|
|
}, {
|
|
|
opacity: 1,
|
|
|
y: 0,
|
|
|
duration: 0.8,
|
|
|
ease: "power2.out"
|
|
|
});
|
|
|
}
|
|
|
if (subtitle) {
|
|
|
gsap.fromTo(subtitle, {
|
|
|
opacity: 0,
|
|
|
y: -15
|
|
|
}, {
|
|
|
opacity: 1,
|
|
|
y: 0,
|
|
|
duration: 0.8,
|
|
|
delay: 0.2,
|
|
|
ease: "power2.out"
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 初始化
|
|
|
updateCarousel();
|
|
|
updateNavigationState();
|
|
|
initGSAPEffects();
|
|
|
});
|
|
|
</script>
|