|
|
<?php
|
|
|
// 文件修改时间:2025-12-11 13:09:50
|
|
|
/**
|
|
|
* Banner区块模板 - 使用原生JavaScript轮播
|
|
|
* 支持自定义器设置和短代码调用
|
|
|
*/
|
|
|
|
|
|
if (!defined('ABSPATH')) {
|
|
|
exit;
|
|
|
}
|
|
|
|
|
|
// 获取短代码参数(如果通过短代码调用)
|
|
|
global $banner_shortcode_atts;
|
|
|
|
|
|
// 确保 $banner_shortcode_atts 是数组
|
|
|
if (!is_array($banner_shortcode_atts)) {
|
|
|
$banner_shortcode_atts = array();
|
|
|
}
|
|
|
|
|
|
$banner_id = isset($banner_shortcode_atts['id']) ? sanitize_html_class($banner_shortcode_atts['id']) : 'nenghui-banner-' . uniqid();
|
|
|
$banner_class = isset($banner_shortcode_atts['class']) ? $banner_shortcode_atts['class'] : '';
|
|
|
$autoplay = isset($banner_shortcode_atts['autoplay']) ? $banner_shortcode_atts['autoplay'] : (get_theme_mod('banner_autoplay', true) ? 'true' : 'false');
|
|
|
|
|
|
// 获取自定义器全局设置
|
|
|
$banner_height = get_theme_mod('banner_height', '500px');
|
|
|
// 处理高度值,确保包含单位
|
|
|
if (is_numeric($banner_height)) {
|
|
|
$banner_height = $banner_height . 'px';
|
|
|
}
|
|
|
// 验证高度值格式
|
|
|
if (!preg_match('/^\d+(\.\d+)?(px|vh)$/', $banner_height)) {
|
|
|
$banner_height = '500px'; // 默认值
|
|
|
}
|
|
|
$autoplay_delay = get_theme_mod('banner_autoplay_delay', 5000);
|
|
|
$overlay_enabled = get_theme_mod('banner_overlay_enabled', true);
|
|
|
$image_only_mode = get_theme_mod('banner_image_only_mode', false);
|
|
|
$navigation_enabled = get_theme_mod('banner_navigation_enabled', true);
|
|
|
$zoom_animation_enabled = get_theme_mod('banner_zoom_animation_enabled', true);
|
|
|
$zoom_animation_duration = get_theme_mod('banner_zoom_animation_duration', 20);
|
|
|
$zoom_animation_scale = get_theme_mod('banner_zoom_animation_scale', 1.08);
|
|
|
// 获取移动端显示控制设置
|
|
|
$show_on_mobile = get_theme_mod('banner_show_on_mobile', true);
|
|
|
|
|
|
// 获取Banner数量设置和显示顺序
|
|
|
$banner_count = get_theme_mod('banner_count', 3);
|
|
|
$banner_display_order = get_theme_mod('banner_display_order', '1,2,3,4,5');
|
|
|
|
|
|
// 解析显示顺序
|
|
|
$order_array = array_map('trim', explode(',', $banner_display_order));
|
|
|
$order_array = array_filter($order_array, function($value) {
|
|
|
return is_numeric($value) && $value >= 1 && $value <= 5;
|
|
|
});
|
|
|
|
|
|
// 如果顺序设置无效,使用默认顺序
|
|
|
if (empty($order_array)) {
|
|
|
$order_array = range(1, $banner_count);
|
|
|
}
|
|
|
|
|
|
// 从自定义器获取Banner数据
|
|
|
$banner_images = array();
|
|
|
$default_placeholder = get_template_directory_uri() . '/assets/images/NaN-img.png';
|
|
|
|
|
|
// 按照设置的顺序处理Banner
|
|
|
foreach ($order_array as $i) {
|
|
|
// 确保不超过设置的Banner数量
|
|
|
if (count($banner_images) >= $banner_count) {
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
$image_url = get_theme_mod('banner_image_' . $i, '');
|
|
|
$video_url = get_theme_mod('banner_video_' . $i, '');
|
|
|
|
|
|
// 增加视频格式验证
|
|
|
if (!empty($video_url)) {
|
|
|
$video_ext = pathinfo(parse_url($video_url, PHP_URL_PATH), PATHINFO_EXTENSION);
|
|
|
if (!in_array(strtolower($video_ext), ['mp4', 'webm', 'ogg'])) {
|
|
|
$video_url = ''; // 过滤非允许格式的视频
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 只有上传了图片或视频的Banner才会被添加到数组中
|
|
|
if (!empty($image_url) || !empty($video_url)) {
|
|
|
$content = get_theme_mod('banner_content_' . $i, '<h2>Banner标题 ' . $i . '</h2><p>这里是Banner描述文字,可以介绍您的产品或服务。</p>');
|
|
|
$button_text = get_theme_mod('banner_button_text_' . $i, '了解更多');
|
|
|
$button_url = get_theme_mod('banner_button_url_' . $i, '#');
|
|
|
|
|
|
$banner_images[] = array(
|
|
|
'image' => $image_url,
|
|
|
'video' => $video_url,
|
|
|
'content' => $content,
|
|
|
'button_text' => $button_text,
|
|
|
'button_url' => $button_url,
|
|
|
'original_index' => $i
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 如果没有有效的Banner图片或视频,显示默认占位图片
|
|
|
if (empty($banner_images)) {
|
|
|
$banner_images[] = array(
|
|
|
'image' => $default_placeholder,
|
|
|
'video' => '',
|
|
|
'content' => '<h2>欢迎使用Banner</h2><p>请在WordPress自定义器中上传Banner图片或视频。</p>',
|
|
|
'button_text' => '了解更多',
|
|
|
'button_url' => '#'
|
|
|
);
|
|
|
}
|
|
|
|
|
|
?>
|
|
|
|
|
|
<style>
|
|
|
/* Mobile Hide Logic - High Priority */
|
|
|
@media (max-width: 991.98px) {
|
|
|
#<?php echo esc_attr($banner_id); ?>.hide-on-mobile,
|
|
|
#<?php echo esc_attr($banner_id); ?>.hide-on-mobile *,
|
|
|
.nenghui-banner.hide-on-mobile,
|
|
|
.nenghui-banner.hide-on-mobile * {
|
|
|
display: none !important;
|
|
|
height: 0 !important;
|
|
|
min-height: 0 !important;
|
|
|
width: 0 !important;
|
|
|
overflow: hidden !important;
|
|
|
visibility: hidden !important;
|
|
|
opacity: 0 !important;
|
|
|
margin: 0 !important;
|
|
|
padding: 0 !important;
|
|
|
border: none !important;
|
|
|
position: absolute !important;
|
|
|
z-index: -9999 !important;
|
|
|
}
|
|
|
}
|
|
|
</style>
|
|
|
|
|
|
<!-- Debug: show_on_mobile = <?php echo var_export($show_on_mobile, true); ?> -->
|
|
|
<!-- Native JS Banner Container -->
|
|
|
<div id="<?php echo esc_attr($banner_id); ?>" class="banner-section nenghui-banner <?php echo esc_attr($banner_class); ?> <?php echo $zoom_animation_enabled ? 'zoom-animation-enabled' : ''; ?> <?php echo ($show_on_mobile === false || $show_on_mobile === '0' || $show_on_mobile === 0) ? 'hide-on-mobile' : ''; ?>" data-autoplay="<?php echo esc_attr($autoplay); ?>" data-delay="<?php echo esc_attr($autoplay_delay); ?>" data-zoom-animation="<?php echo esc_attr($zoom_animation_enabled ? 'true' : 'false'); ?>" data-aos="fade-up">
|
|
|
<!-- Banner wrapper -->
|
|
|
<div class="banner-wrapper" data-aos="fade-up" data-aos-delay="200">
|
|
|
<?php foreach ($banner_images as $index => $banner): ?>
|
|
|
<!-- Slide -->
|
|
|
<div class="banner-slide <?php echo $index === 0 ? 'active' : ''; ?>" data-has-video="<?php echo !empty($banner['video']) ? 'true' : 'false'; ?>" <?php if (!empty($banner['video'])): ?>data-video-src="<?php echo esc_url($banner['video']); ?>"<?php endif; ?> <?php if (empty($banner['video'])): ?>style="background-image: url('<?php echo esc_url($banner['image']); ?>')"<?php endif; ?>>
|
|
|
<?php if (!empty($banner['video'])): ?>
|
|
|
<?php if (!empty($banner['image'])): ?>
|
|
|
<img class="banner-video-fallback" src="<?php echo esc_url($banner['image']); ?>" alt="Video fallback" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; z-index: 1;">
|
|
|
<?php endif; ?>
|
|
|
<div class="video-loading"><div class="spinner"></div></div>
|
|
|
<?php endif; ?>
|
|
|
<?php if ($overlay_enabled): ?>
|
|
|
<div class="banner-overlay"></div>
|
|
|
<?php endif; ?>
|
|
|
<?php if (!$image_only_mode && empty($banner['video'])): ?>
|
|
|
<div class="banner-content" data-aos="fade-up" data-aos-delay="400">
|
|
|
<div class="container-fluid">
|
|
|
<div class="row">
|
|
|
<div class="col-lg-8 offset-lg-1">
|
|
|
<div class="banner-text-content">
|
|
|
<?php echo wp_kses_post($banner['content']); ?>
|
|
|
</div>
|
|
|
<a href="<?php echo esc_url($banner['button_url']); ?>" class="btn btn-primary banner-btn">
|
|
|
<?php echo esc_html($banner['button_text']); ?>
|
|
|
</a>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<?php endif; ?>
|
|
|
</div>
|
|
|
<?php endforeach; ?>
|
|
|
</div>
|
|
|
|
|
|
<!-- Pagination dots -->
|
|
|
<?php if (count($banner_images) > 1): ?>
|
|
|
<div class="banner-pagination" data-aos="fade-up" data-aos-delay="600">
|
|
|
<?php foreach ($banner_images as $index => $banner): ?>
|
|
|
<span class="pagination-dot <?php echo $index === 0 ? 'active' : ''; ?>" data-slide="<?php echo $index; ?>"></span>
|
|
|
<?php endforeach; ?>
|
|
|
</div>
|
|
|
<?php endif; ?>
|
|
|
|
|
|
<!-- Navigation buttons -->
|
|
|
<?php if ($navigation_enabled && count($banner_images) > 1): ?>
|
|
|
<div class="banner-button-prev" data-aos="fade-up" data-aos-delay="800">‹</div>
|
|
|
<div class="banner-button-next" data-aos="fade-up" data-aos-delay="800">›</div>
|
|
|
<?php endif; ?>
|
|
|
</div>
|
|
|
|
|
|
<?php if ($show_on_mobile === false || $show_on_mobile === '0' || $show_on_mobile === 0): ?>
|
|
|
<script>
|
|
|
(function() {
|
|
|
function hideMobileBanner() {
|
|
|
if (window.innerWidth <= 992) {
|
|
|
var banner = document.getElementById('<?php echo esc_js($banner_id); ?>');
|
|
|
if (banner) {
|
|
|
banner.style.display = 'none';
|
|
|
banner.style.height = '0';
|
|
|
banner.style.overflow = 'hidden';
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
// Run on load and resize
|
|
|
window.addEventListener('load', hideMobileBanner);
|
|
|
window.addEventListener('resize', hideMobileBanner);
|
|
|
// Run immediately
|
|
|
hideMobileBanner();
|
|
|
})();
|
|
|
</script>
|
|
|
<?php endif; ?>
|
|
|
|
|
|
<style>
|
|
|
.nenghui-banner {
|
|
|
width: 100%;
|
|
|
height: <?php echo esc_attr($banner_height); ?>;
|
|
|
position: relative;
|
|
|
overflow: hidden;
|
|
|
margin: 0;
|
|
|
padding: 0;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-wrapper {
|
|
|
position: relative;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-slide {
|
|
|
position: absolute;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
background-size: cover;
|
|
|
background-position: center;
|
|
|
background-repeat: no-repeat;
|
|
|
opacity: 0;
|
|
|
transition: opacity 0.6s ease-in-out;
|
|
|
z-index: 1;
|
|
|
}
|
|
|
|
|
|
/* 背景图片缩放动画效果 */
|
|
|
.nenghui-banner.zoom-animation-enabled .banner-slide {
|
|
|
background-size: cover;
|
|
|
transform: scale(1);
|
|
|
transition: opacity 0.6s ease-in-out, transform 0.6s ease-out;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner.zoom-animation-enabled .banner-slide.active {
|
|
|
animation: bannerZoomIn <?php echo esc_attr($zoom_animation_duration); ?>s ease-out forwards;
|
|
|
}
|
|
|
|
|
|
@keyframes bannerZoomIn {
|
|
|
0% {
|
|
|
transform: scale(1);
|
|
|
}
|
|
|
5% {
|
|
|
transform: scale(<?php echo esc_attr(1 + ($zoom_animation_scale - 1) * 0.05); ?>);
|
|
|
}
|
|
|
100% {
|
|
|
transform: scale(<?php echo esc_attr($zoom_animation_scale); ?>);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 确保非活动幻灯片保持原始大小,添加平滑过渡 */
|
|
|
.nenghui-banner.zoom-animation-enabled .banner-slide:not(.active) {
|
|
|
transform: scale(1);
|
|
|
animation: none;
|
|
|
transition: opacity 0.6s ease-in-out, transform 0.6s ease-out;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-slide.active {
|
|
|
opacity: 1;
|
|
|
z-index: 2;
|
|
|
}
|
|
|
|
|
|
/* 视频背景样式 */
|
|
|
.nenghui-banner .banner-video {
|
|
|
position: absolute;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
object-fit: cover;
|
|
|
z-index: 1;
|
|
|
pointer-events: none; /* 禁用用户交互 */
|
|
|
}
|
|
|
|
|
|
/* 视频幻灯片特殊处理 */
|
|
|
.nenghui-banner .banner-slide:has(.banner-video) {
|
|
|
background-image: none !important;
|
|
|
}
|
|
|
|
|
|
/* 视频缩放动画效果 */
|
|
|
.nenghui-banner.zoom-animation-enabled .banner-slide .banner-video {
|
|
|
transform: scale(1);
|
|
|
transition: transform 0.6s ease-out;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner.zoom-animation-enabled .banner-slide.active .banner-video {
|
|
|
animation: videoZoomIn <?php echo esc_attr($zoom_animation_duration); ?>s ease-out forwards;
|
|
|
}
|
|
|
|
|
|
@keyframes videoZoomIn {
|
|
|
0% {
|
|
|
transform: scale(1);
|
|
|
}
|
|
|
5% {
|
|
|
transform: scale(<?php echo esc_attr(1 + ($zoom_animation_scale - 1) * 0.05); ?>);
|
|
|
}
|
|
|
100% {
|
|
|
transform: scale(<?php echo esc_attr($zoom_animation_scale); ?>);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 确保非活动视频保持原始大小 */
|
|
|
.nenghui-banner.zoom-animation-enabled .banner-slide:not(.active) .banner-video {
|
|
|
transform: scale(1);
|
|
|
animation: none;
|
|
|
transition: transform 0.6s ease-out;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-overlay {
|
|
|
position: absolute;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
background: rgba(0, 0, 0, 0.4);
|
|
|
z-index: 3;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-content {
|
|
|
position: absolute;
|
|
|
top: 50%;
|
|
|
left: 50%;
|
|
|
width: 100%;
|
|
|
max-width: 80%;
|
|
|
transform: translate(-50%, -50%);
|
|
|
z-index: 4;
|
|
|
color: white;
|
|
|
}
|
|
|
|
|
|
/* 文字内容动画效果 */
|
|
|
.nenghui-banner .banner-text-content {
|
|
|
opacity: 0;
|
|
|
transform: translateY(30px);
|
|
|
transition: all 0.8s ease-out;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-btn {
|
|
|
opacity: 0;
|
|
|
transform: translateY(30px);
|
|
|
transition: all 0.8s ease-out 0.3s;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-slide.active .banner-text-content {
|
|
|
opacity: 1;
|
|
|
transform: translateY(0);
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-slide.active .banner-btn {
|
|
|
opacity: 1;
|
|
|
transform: translateY(0);
|
|
|
}
|
|
|
|
|
|
/* 响应式设计 */
|
|
|
@media (max-width: 768px) {
|
|
|
.nenghui-banner .banner-content {
|
|
|
max-width: 90%;
|
|
|
padding: 0 15px;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-text-content {
|
|
|
transform: translateY(20px);
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-btn {
|
|
|
transform: translateY(20px);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@media (max-width: 480px) {
|
|
|
.nenghui-banner .banner-content {
|
|
|
max-width: 95%;
|
|
|
padding: 0 10px;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-text-content {
|
|
|
transform: translateY(15px);
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-btn {
|
|
|
transform: translateY(15px);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 减少动画模式支持 */
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
|
.nenghui-banner .banner-text-content,
|
|
|
.nenghui-banner .banner-btn {
|
|
|
transition: none;
|
|
|
opacity: 1;
|
|
|
transform: none;
|
|
|
}
|
|
|
|
|
|
/* 禁用背景图片缩放动画 */
|
|
|
.nenghui-banner.zoom-animation-enabled .banner-slide,
|
|
|
.nenghui-banner.zoom-animation-enabled .banner-slide.active,
|
|
|
.nenghui-banner.zoom-animation-enabled .banner-slide:not(.active) {
|
|
|
animation: none;
|
|
|
transform: scale(1) !important;
|
|
|
background-size: cover;
|
|
|
}
|
|
|
|
|
|
/* 禁用视频缩放动画 */
|
|
|
.nenghui-banner.zoom-animation-enabled .banner-slide .banner-video,
|
|
|
.nenghui-banner.zoom-animation-enabled .banner-slide.active .banner-video,
|
|
|
.nenghui-banner.zoom-animation-enabled .banner-slide:not(.active) .banner-video {
|
|
|
animation: none !important;
|
|
|
transform: scale(1) !important;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 移动设备视频优化 */
|
|
|
@media (max-width: 768px) {
|
|
|
.nenghui-banner .banner-video {
|
|
|
/* 确保视频在移动设备上正确显示 */
|
|
|
object-fit: cover;
|
|
|
object-position: center;
|
|
|
}
|
|
|
|
|
|
/* 移动设备上禁用视频缩放动画以提升性能 */
|
|
|
.nenghui-banner.zoom-animation-enabled .banner-slide .banner-video,
|
|
|
.nenghui-banner.zoom-animation-enabled .banner-slide.active .banner-video {
|
|
|
animation: none;
|
|
|
transform: scale(1) !important;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-pagination {
|
|
|
position: absolute;
|
|
|
bottom: 20px;
|
|
|
left: 50%;
|
|
|
transform: translateX(-50%);
|
|
|
display: flex;
|
|
|
gap: 10px;
|
|
|
z-index: 5;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .pagination-dot {
|
|
|
width: 12px;
|
|
|
height: 12px;
|
|
|
border-radius: 50%;
|
|
|
background: rgba(255, 255, 255, 0.5);
|
|
|
cursor: pointer;
|
|
|
transition: background 0.3s ease;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .pagination-dot.active {
|
|
|
background: rgba(255, 255, 255, 1);
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-button-prev,
|
|
|
.nenghui-banner .banner-button-next {
|
|
|
position: absolute;
|
|
|
top: 50%;
|
|
|
transform: translateY(-50%);
|
|
|
width: 50px;
|
|
|
height: 50px;
|
|
|
background: rgb(46 182 170 / 40%);
|
|
|
color: white;
|
|
|
border: none;
|
|
|
border-radius: 50%;
|
|
|
font-size: 24px;
|
|
|
cursor: pointer;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
transition: all 0.3s ease;
|
|
|
z-index: 5;
|
|
|
user-select: none;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-button-prev:hover,
|
|
|
.nenghui-banner .banner-button-next:hover {
|
|
|
background: rgb(46 182 170 / 70%);
|
|
|
border: 1px solid #eee;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-button-prev {
|
|
|
left: 20px;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .banner-button-next {
|
|
|
right: 20px;
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .video-loading {
|
|
|
position: absolute;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
display: none;
|
|
|
z-index: 2;
|
|
|
background: rgba(0, 0, 0, 0.15);
|
|
|
backdrop-filter: blur(2px);
|
|
|
}
|
|
|
|
|
|
.nenghui-banner .video-loading .spinner {
|
|
|
position: absolute;
|
|
|
top: 50%;
|
|
|
left: 50%;
|
|
|
width: 36px;
|
|
|
height: 36px;
|
|
|
margin-left: -18px;
|
|
|
margin-top: -18px;
|
|
|
border: 3px solid rgba(255, 255, 255, 0.5);
|
|
|
border-top-color: #2eb6aa;
|
|
|
border-radius: 50%;
|
|
|
animation: bannerSpin 0.8s linear infinite;
|
|
|
}
|
|
|
|
|
|
@keyframes bannerSpin {
|
|
|
to { transform: rotate(360deg); }
|
|
|
}
|
|
|
</style>
|
|
|
|
|
|
<script>
|
|
|
(function() {
|
|
|
/**
|
|
|
* 原生JavaScript Banner轮播功能
|
|
|
* 替代Swiper库,防止多个轮播初始化造成混乱
|
|
|
*/
|
|
|
function initNativeBanner() {
|
|
|
const bannerId = '<?php echo esc_js($banner_id); ?>';
|
|
|
const bannerElement = document.getElementById(bannerId);
|
|
|
|
|
|
if (!bannerElement) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 检查是否已经初始化过
|
|
|
if (bannerElement.bannerInstance) {
|
|
|
bannerElement.bannerInstance.destroy();
|
|
|
}
|
|
|
|
|
|
const slides = bannerElement.querySelectorAll('.banner-slide');
|
|
|
const dots = bannerElement.querySelectorAll('.pagination-dot');
|
|
|
const prevBtn = bannerElement.querySelector('.banner-button-prev');
|
|
|
const nextBtn = bannerElement.querySelector('.banner-button-next');
|
|
|
|
|
|
if (slides.length <= 1) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 查找当前活动的幻灯片索引
|
|
|
let currentSlide = 0;
|
|
|
slides.forEach((slide, index) => {
|
|
|
if (slide.classList.contains('active')) {
|
|
|
currentSlide = index;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
let autoplayTimer = null;
|
|
|
const autoplay = bannerElement.getAttribute('data-autoplay') === 'true';
|
|
|
const delay = parseInt(bannerElement.getAttribute('data-delay')) || 5000;
|
|
|
|
|
|
|
|
|
function releaseSlideVideo(slide) {
|
|
|
const video = slide.querySelector('.banner-video');
|
|
|
if (!video) return;
|
|
|
try { video.pause(); } catch (e) {}
|
|
|
const source = video.querySelector('source');
|
|
|
if (source) source.src = '';
|
|
|
video.removeAttribute('src');
|
|
|
try { video.load(); } catch (e) {}
|
|
|
if (video.parentNode) video.parentNode.removeChild(video);
|
|
|
const fallbackImg = slide.querySelector('.banner-video-fallback');
|
|
|
if (fallbackImg) fallbackImg.style.display = 'block';
|
|
|
const loadingEl = slide.querySelector('.video-loading');
|
|
|
if (loadingEl) loadingEl.style.display = 'none';
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取或创建视频元素,避免重复创建
|
|
|
*/
|
|
|
function getOrCreateVideoElement(slide, src, isMobile) {
|
|
|
let video = slide.querySelector('.banner-video');
|
|
|
if (video) return video;
|
|
|
|
|
|
if (!src) return null;
|
|
|
|
|
|
const fallbackImg = slide.querySelector('.banner-video-fallback');
|
|
|
const loadingEl = slide.querySelector('.video-loading');
|
|
|
|
|
|
video = document.createElement('video');
|
|
|
video.className = 'banner-video';
|
|
|
video.muted = true;
|
|
|
video.loop = true;
|
|
|
video.playsInline = true;
|
|
|
video.preload = isMobile ? 'metadata' : 'auto';
|
|
|
|
|
|
const source = document.createElement('source');
|
|
|
source.src = src;
|
|
|
source.type = 'video/mp4';
|
|
|
video.appendChild(source);
|
|
|
|
|
|
if (fallbackImg && fallbackImg.parentNode) {
|
|
|
slide.insertBefore(video, fallbackImg);
|
|
|
} else {
|
|
|
slide.appendChild(video);
|
|
|
}
|
|
|
|
|
|
// 添加事件监听
|
|
|
video.addEventListener('error', function() {
|
|
|
if (fallbackImg) fallbackImg.style.display = 'block';
|
|
|
video.style.display = 'none';
|
|
|
if (loadingEl) loadingEl.style.display = 'none';
|
|
|
});
|
|
|
|
|
|
video.addEventListener('loadeddata', function() {
|
|
|
if (slide.classList.contains('active') && loadingEl) loadingEl.style.display = 'none';
|
|
|
if (fallbackImg) fallbackImg.style.display = 'none';
|
|
|
});
|
|
|
|
|
|
video.addEventListener('ended', function() {
|
|
|
video.currentTime = 0;
|
|
|
video.play().catch(function(){});
|
|
|
});
|
|
|
|
|
|
return video;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 控制视频播放
|
|
|
*/
|
|
|
function controlVideos(activeIndex) {
|
|
|
const isMobile = window.innerWidth <= 768;
|
|
|
const conn = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
|
|
|
const saveData = !!(conn && conn.saveData);
|
|
|
const effectiveType = (conn && conn.effectiveType) || '';
|
|
|
const preloadNeighbors = !isMobile && !saveData && effectiveType !== '2g' && effectiveType !== 'slow-2g';
|
|
|
const prevIndex = (activeIndex - 1 + slides.length) % slides.length;
|
|
|
const nextIndex = (activeIndex + 1) % slides.length;
|
|
|
|
|
|
slides.forEach((slide, index) => {
|
|
|
const hasVideo = slide.getAttribute('data-has-video') === 'true';
|
|
|
if (!hasVideo) return;
|
|
|
|
|
|
const src = slide.getAttribute('data-video-src');
|
|
|
const loadingEl = slide.querySelector('.video-loading');
|
|
|
const fallbackImg = slide.querySelector('.banner-video-fallback');
|
|
|
|
|
|
if (index === activeIndex) {
|
|
|
const video = getOrCreateVideoElement(slide, src, isMobile);
|
|
|
|
|
|
if (video) {
|
|
|
if (loadingEl) loadingEl.style.display = 'block';
|
|
|
const p = video.play();
|
|
|
if (p && typeof p.then === 'function') {
|
|
|
p.then(function(){
|
|
|
if (loadingEl) loadingEl.style.display = 'none';
|
|
|
if (fallbackImg) fallbackImg.style.display = 'none';
|
|
|
})
|
|
|
.catch(function(){
|
|
|
if (fallbackImg) fallbackImg.style.display = 'block';
|
|
|
video.style.display = 'none';
|
|
|
if (loadingEl) loadingEl.style.display = 'none';
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
} else if (preloadNeighbors && (index === prevIndex || index === nextIndex)) {
|
|
|
const video = getOrCreateVideoElement(slide, src, isMobile);
|
|
|
if (video) {
|
|
|
// 预加载但不播放
|
|
|
if (video.preload === 'metadata' && !isMobile) {
|
|
|
video.preload = 'auto';
|
|
|
}
|
|
|
try { video.load(); } catch(e) {}
|
|
|
}
|
|
|
if (loadingEl) loadingEl.style.display = 'none';
|
|
|
} else {
|
|
|
releaseSlideVideo(slide);
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 初始化视频事件监听
|
|
|
*/
|
|
|
function initVideoEvents() {}
|
|
|
|
|
|
/**
|
|
|
* 重新启动缩放动画
|
|
|
*/
|
|
|
function restartZoomAnimation(slide) {
|
|
|
const zoomEnabled = bannerElement.getAttribute('data-zoom-animation') === 'true';
|
|
|
if (zoomEnabled && bannerElement.classList.contains('zoom-animation-enabled')) {
|
|
|
// 处理视频缩放动画
|
|
|
const video = slide.querySelector('.banner-video');
|
|
|
if (video) {
|
|
|
video.style.transform = 'scale(1)';
|
|
|
video.style.animation = 'none';
|
|
|
|
|
|
// 强制重绘
|
|
|
video.offsetHeight;
|
|
|
|
|
|
// 延迟启动动画
|
|
|
setTimeout(() => {
|
|
|
video.style.animation = '';
|
|
|
}, 100);
|
|
|
} else {
|
|
|
// 处理图片缩放动画
|
|
|
slide.style.transform = 'scale(1)';
|
|
|
slide.style.animation = 'none';
|
|
|
|
|
|
// 强制重绘
|
|
|
slide.offsetHeight;
|
|
|
|
|
|
// 延迟启动动画
|
|
|
setTimeout(() => {
|
|
|
slide.style.animation = '';
|
|
|
}, 100);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 切换到指定幻灯片
|
|
|
*/
|
|
|
function goToSlide(index) {
|
|
|
// 验证索引有效性
|
|
|
if (index < 0 || index >= slides.length) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 移除所有活动状态
|
|
|
slides.forEach((slide, slideIndex) => {
|
|
|
slide.classList.remove('active');
|
|
|
// 重置文字动画状态
|
|
|
const textContent = slide.querySelector('.banner-text-content');
|
|
|
const btnContent = slide.querySelector('.banner-btn');
|
|
|
if (textContent) {
|
|
|
textContent.style.opacity = '';
|
|
|
textContent.style.transform = '';
|
|
|
}
|
|
|
if (btnContent) {
|
|
|
btnContent.style.opacity = '';
|
|
|
btnContent.style.transform = '';
|
|
|
}
|
|
|
});
|
|
|
dots.forEach(dot => dot.classList.remove('active'));
|
|
|
|
|
|
// 设置新的活动状态
|
|
|
slides[index].classList.add('active');
|
|
|
if (dots[index]) {
|
|
|
dots[index].classList.add('active');
|
|
|
}
|
|
|
|
|
|
// 控制视频播放
|
|
|
controlVideos(index);
|
|
|
|
|
|
// 重新启动当前幻灯片的缩放动画
|
|
|
restartZoomAnimation(slides[index]);
|
|
|
|
|
|
// 更新当前幻灯片索引
|
|
|
currentSlide = index;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 下一张幻灯片
|
|
|
*/
|
|
|
function nextSlide() {
|
|
|
if (slides.length <= 1) return;
|
|
|
const next = (currentSlide + 1) % slides.length;
|
|
|
goToSlide(next);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 上一张幻灯片
|
|
|
*/
|
|
|
function prevSlide() {
|
|
|
if (slides.length <= 1) return;
|
|
|
const prev = (currentSlide - 1 + slides.length) % slides.length;
|
|
|
goToSlide(prev);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 开始自动播放
|
|
|
*/
|
|
|
function startAutoplay() {
|
|
|
if (autoplay && slides.length > 1) {
|
|
|
// 清除可能存在的定时器
|
|
|
if (autoplayTimer) {
|
|
|
clearInterval(autoplayTimer);
|
|
|
}
|
|
|
autoplayTimer = setInterval(nextSlide, delay);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 停止自动播放
|
|
|
*/
|
|
|
function stopAutoplay() {
|
|
|
if (autoplayTimer) {
|
|
|
clearInterval(autoplayTimer);
|
|
|
autoplayTimer = null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 重启自动播放
|
|
|
*/
|
|
|
function restartAutoplay() {
|
|
|
stopAutoplay();
|
|
|
startAutoplay();
|
|
|
}
|
|
|
|
|
|
// 绑定分页点击事件
|
|
|
dots.forEach((dot, index) => {
|
|
|
dot.addEventListener('click', () => {
|
|
|
goToSlide(index);
|
|
|
restartAutoplay();
|
|
|
});
|
|
|
});
|
|
|
|
|
|
// 绑定导航按钮事件
|
|
|
if (prevBtn) {
|
|
|
prevBtn.addEventListener('click', () => {
|
|
|
prevSlide();
|
|
|
restartAutoplay();
|
|
|
});
|
|
|
}
|
|
|
|
|
|
if (nextBtn) {
|
|
|
nextBtn.addEventListener('click', () => {
|
|
|
nextSlide();
|
|
|
restartAutoplay();
|
|
|
});
|
|
|
}
|
|
|
|
|
|
// 鼠标悬停时暂停自动播放
|
|
|
bannerElement.addEventListener('mouseenter', stopAutoplay);
|
|
|
bannerElement.addEventListener('mouseleave', startAutoplay);
|
|
|
|
|
|
// 键盘导航支持
|
|
|
document.addEventListener('keydown', (e) => {
|
|
|
if (bannerElement.matches(':hover')) {
|
|
|
if (e.key === 'ArrowLeft') {
|
|
|
prevSlide();
|
|
|
restartAutoplay();
|
|
|
} else if (e.key === 'ArrowRight') {
|
|
|
nextSlide();
|
|
|
restartAutoplay();
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 触摸滑动支持
|
|
|
let touchStartX = 0;
|
|
|
let touchEndX = 0;
|
|
|
|
|
|
bannerElement.addEventListener('touchstart', (e) => {
|
|
|
touchStartX = e.changedTouches[0].screenX;
|
|
|
});
|
|
|
|
|
|
bannerElement.addEventListener('touchend', (e) => {
|
|
|
touchEndX = e.changedTouches[0].screenX;
|
|
|
const diff = touchStartX - touchEndX;
|
|
|
|
|
|
if (Math.abs(diff) > 50) { // 最小滑动距离
|
|
|
if (diff > 0) {
|
|
|
nextSlide();
|
|
|
} else {
|
|
|
prevSlide();
|
|
|
}
|
|
|
restartAutoplay();
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 销毁方法
|
|
|
const destroy = () => {
|
|
|
stopAutoplay();
|
|
|
slides.forEach(slide => releaseSlideVideo(slide));
|
|
|
dots.forEach(dot => {
|
|
|
dot.removeEventListener('click', () => {});
|
|
|
});
|
|
|
if (prevBtn) prevBtn.removeEventListener('click', () => {});
|
|
|
if (nextBtn) nextBtn.removeEventListener('click', () => {});
|
|
|
bannerElement.removeEventListener('mouseenter', stopAutoplay);
|
|
|
bannerElement.removeEventListener('mouseleave', startAutoplay);
|
|
|
bannerElement.bannerInstance = null;
|
|
|
};
|
|
|
|
|
|
// 存储实例到元素上
|
|
|
bannerElement.bannerInstance = {
|
|
|
goToSlide,
|
|
|
nextSlide,
|
|
|
prevSlide,
|
|
|
startAutoplay,
|
|
|
stopAutoplay,
|
|
|
destroy
|
|
|
};
|
|
|
|
|
|
// 初始化视频事件监听
|
|
|
initVideoEvents();
|
|
|
|
|
|
// 确保当前幻灯片状态正确
|
|
|
if (slides.length > 0) {
|
|
|
// 如果没有活动幻灯片,设置第一张为活动
|
|
|
const hasActiveSlide = Array.from(slides).some(slide => slide.classList.contains('active'));
|
|
|
if (!hasActiveSlide) {
|
|
|
goToSlide(0);
|
|
|
} else {
|
|
|
// 初始化视频播放状态
|
|
|
controlVideos(currentSlide);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 开始自动播放
|
|
|
startAutoplay();
|
|
|
|
|
|
}
|
|
|
|
|
|
// 多种初始化方式确保兼容性
|
|
|
if (document.readyState === 'loading') {
|
|
|
document.addEventListener('DOMContentLoaded', initNativeBanner);
|
|
|
} else {
|
|
|
initNativeBanner();
|
|
|
}
|
|
|
|
|
|
// 备用初始化
|
|
|
window.addEventListener('load', function() {
|
|
|
setTimeout(initNativeBanner, 100);
|
|
|
});
|
|
|
})();
|
|
|
</script>
|