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.

548 lines
16 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?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>