微件

微件:Carousel

来自卡厄思梦境WIKI

律Rhyme留言 | 贡献2025年10月14日 (二) 14:06的版本 (创建页面,内容为“<style> .carousel-container { width: 100%; height: 280px; position: relative; overflow: hidden; background: #f0f0f0; border-radius: 6px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .carousel-wrapper { display: flex; height: 100%; transition: transform 0.5s ease; will-change: transform; } .carousel-slide { min-width: 100%; height: 100%; position: relative; } .carousel-slide img, .carousel-slide a.image img…”)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)

<style> .carousel-container {

   width: 100%;
   height: 280px;
   position: relative;
   overflow: hidden;
   background: #f0f0f0;
   border-radius: 6px;
   box-shadow: 0 2px 10px rgba(0,0,0,0.1);

}

.carousel-wrapper {

   display: flex;
   height: 100%;
   transition: transform 0.5s ease;
   will-change: transform;

}

.carousel-slide {

   min-width: 100%;
   height: 100%;
   position: relative;

}

.carousel-slide img, .carousel-slide a.image img {

   width: 100% !important;
   height: 280px !important;
   object-fit: cover;
   display: block;

}

.carousel-titles-overlay {

   position: absolute;
   left: 0; right: 0; bottom: 0;
   background: linear-gradient(to top, rgba(0,0,0,0.28), rgba(0,0,0,0.12));
   padding: 10px 0 0px;
   z-index: 10;

}

.carousel-titles-wrapper {

   display: flex;
   align-items: center;
   position: relative;
   padding: 0 50px;

}

.carousel-titles-container {

   max-width: calc(100% - 120px);
   display: flex;
   justify-content: center;
   align-items: flex-end;
   gap: 12px;
   margin: 0 auto;

}

.carousel-title-item {

   transition: all 0.3s ease;
   min-width: 0;
   flex: 1;
   max-width: 200px;
   cursor: pointer;

}

.carousel-title-item:hover .title-text {

   opacity: 1 !important;

}

.carousel-title-item.active .title-text {

   opacity: 1 !important;
   font-weight: bold;

}

.carousel-title-item.active .title-indicator {

   background: #ff6600 !important;

}

.title-text {

   color: #fff;
   font-size: 13px;
   padding: 6px 8px;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
   text-align: center;
   opacity: 0.75;

}

.title-indicator {

   height: 2px;
   background: transparent;
   margin-top: 6px;
   transition: all 0.3s ease;

}

.carousel-btn {

   transition: all 0.3s;
   user-select: none;
   cursor: pointer;
   z-index: 20;
   opacity: 0.85;

}

.carousel-btn:hover {

   opacity: 1 !important;
   transform: translateY(-50%) scale(1.08);

}

.carousel-btn img {

   width: 100%;
   height: 100%;
   object-fit: contain;

}

.carousel-btn a.image {

   display: block;
   cursor: default;
   user-select: none;

}

@media (max-width: 1024px) {

   .carousel-titles-container { max-width: calc(100% - 100px); }

}

@media (max-width: 768px) {

   .carousel-titles-container {
       gap: 8px !important;
   }
   .carousel-title-item {
       max-width: 150px !important;
   }
   .title-text {
       font-size: 12px !important;
       padding: 5px 6px !important;
   }
   .carousel-btn {
       width: 25px !important;
       height: 25px !important;
   }
   .carousel-titles-wrapper {
       padding: 0 40px !important;
   }
   .carousel-btn.carousel-prev {
       left: 8px !important;
   }
   .carousel-btn.carousel-next {
       right: 8px !important;
   }

}

@media (max-width: 480px) {

   .carousel-title-item {
       max-width: 110px !important;
   }
   .title-text {
       font-size: 11px !important;
       padding: 4px 5px !important;
   }
   .carousel-btn {
       width: 22px !important;
       height: 22px !important;
   }

}

.carousel-container.single .carousel-btn { display: none; }

.carousel-slide .thumb, .carousel-slide .thumbinner {

   width: 100% !important;
   height: 100% !important;
   overflow: hidden;
   border: 0;
   background: none;
   box-shadow: none;

}

.carousel-container img {

   user-select: none;
   -webkit-user-drag: none;

}

.carousel-container.grab { cursor: grab; } .carousel-container.grabbing { cursor: grabbing; } </style>

<script> (function () {

 'use strict';
 
 function initCarousel(root) {
   if (!root || root.__inited) return;
   root.__inited = true;
   const wrapper = root.querySelector('.carousel-wrapper');
   const slides = Array.from(root.querySelectorAll('.carousel-slide'));
   const titles = Array.from(root.querySelectorAll('.carousel-title-item'));
   const btnPrev = root.querySelector('.carousel-prev');
   const btnNext = root.querySelector('.carousel-next');
   if (!wrapper || !slides.length) {
     root.style.display = 'none';
     return;
   }
   // 单张图隐藏按钮
   if (slides.length === 1) {
     root.classList.add('single');
   }
   // 标题索引与幻灯索引对齐
   titles.forEach((t, i) => {
     t.dataset.slide = String(i);
   });
   let index = 0;
   let timer = null;
   const autoplay = (root.getAttribute('data-autoplay') || '1') !== '0';
   const interval = Math.max(1500, parseInt(root.getAttribute('data-interval') || '4000', 10) || 4000);
   function update() {
     wrapper.style.transform = 'translateX(' + (-index * 100) + '%)';
     titles.forEach((t, i) => {
       if (i === index) t.classList.add('active');
       else t.classList.remove('active');
       const text = t.querySelector('.title-text');
       const ind = t.querySelector('.title-indicator');
       if (text) text.style.opacity = i === index ? '1' : '0.75';
       if (ind) ind.style.background = i === index ? '#ff6600' : 'transparent';
     });
   }
   function next() {
     index = (index + 1) % slides.length;
     update();
   }
   function prev() {
     index = (index - 1 + slides.length) % slides.length;
     update();
   }
   // 标题点击
   titles.forEach((t) => {
     t.addEventListener('click', function () {
       const i = parseInt(t.dataset.slide || '0', 10) || 0;
       index = Math.min(Math.max(i, 0), slides.length - 1);
       update();
       restartAutoplay();
     });
   });
   // 按钮点击
   if (btnPrev) {
     btnPrev.addEventListener('click', function () {
       prev();
       restartAutoplay();
     });
   }
   if (btnNext) {
     btnNext.addEventListener('click', function () {
       next();
       restartAutoplay();
     });
   }
   // 自动播放控制
   function startAutoplay() {
     if (!autoplay || slides.length <= 1) return;
     stopAutoplay();
     timer = setInterval(next, interval);
   }
   function stopAutoplay() {
     if (timer) {
       clearInterval(timer);
       timer = null;
     }
   }
   function restartAutoplay() {
     stopAutoplay();
     startAutoplay();
   }
   // 悬停/聚焦暂停
   root.addEventListener('mouseenter', stopAutoplay);
   root.addEventListener('mouseleave', startAutoplay);
   root.addEventListener('focusin', stopAutoplay);
   root.addEventListener('focusout', startAutoplay);
   // 触摸滑动
   let startX = 0;
   let curX = 0;
   let dragging = false;
   const threshold = 30;
   root.addEventListener(
     'touchstart',
     function (e) {
       if (!e.touches || !e.touches.length) return;
       startX = e.touches[0].clientX;
       curX = startX;
       dragging = true;
       root.classList.add('grabbing');
       stopAutoplay();
     },
     { passive: true }
   );
   root.addEventListener(
     'touchmove',
     function (e) {
       if (!dragging || !e.touches || !e.touches.length) return;
       curX = e.touches[0].clientX;
       const dx = curX - startX;
       wrapper.style.transform = 'translateX(calc(' + (-index * 100) + '% + ' + dx + 'px))';
     },
     { passive: true }
   );
   root.addEventListener('touchend', function () {
     if (!dragging) return;
     const dx = curX - startX;
     root.classList.remove('grabbing');
     dragging = false;
     if (Math.abs(dx) > threshold) {
       if (dx < 0) next();
       else prev();
     } else {
       update();
     }
     startAutoplay();
   });
   // 鼠标拖动(可选)
   let mouseDown = false;
   let mStartX = 0;
   root.addEventListener('mousedown', function (e) {
     mouseDown = true;
     mStartX = e.clientX;
     root.classList.add('grab');
     stopAutoplay();
   });
   window.addEventListener('mouseup', function (e) {
     if (!mouseDown) return;
     const dx = e.clientX - mStartX;
     mouseDown = false;
     root.classList.remove('grab');
     if (Math.abs(dx) > threshold) {
       if (dx < 0) next();
       else prev();
     } else {
       update();
     }
     startAutoplay();
   });
   // 初始化
   update();
   startAutoplay();
 } // <- 确保此处仅关闭 initCarousel 函数
 function initAll(context) {
   const scope = context && context.querySelectorAll ? context : document;
   scope.querySelectorAll('.carousel-container').forEach(initCarousel);
 }
 // 初次加载
 if (document.readyState === 'loading') {
   document.addEventListener('DOMContentLoaded', function () {
     initAll();
   });
 } else {
   initAll();
 }
 // 动态内容(如可视化编辑器或AJAX)再次初始化
 if (window.mw && mw.hook) {
   mw.hook('wikipage.content').add(function (content) {
     // content 可能是 jQuery 对象,也可能是原生节点
     if (content && content[0] && content.find) {
       // jQuery 对象
       content.find('.carousel-container').each(function () {
         initCarousel(this);
       });
     } else if (content && content.querySelectorAll) {
       // 原生节点
       initAll(content);
     } else {
       initAll();
     }
   });
 }

})();

$(function() {

   // 加载CSS
   mw.loader.load('/index.php?title=Template:Carousel/styles.css&action=raw&ctype=text/css', 'text/css');
   $('.carousel-container').each(function() {
       var $container = $(this);
       var $wrapper = $container.find('.carousel-wrapper');
       var $slides = $container.find('.carousel-slide');
       var $titleItems = $container.find('.carousel-title-item');
       var slideCount = $slides.length;
       var currentSlide = 0;
       var autoPlayInterval;
       var isTransitioning = false;
       
       // 切换到指定幻灯片
       function goToSlide(index) {
           if (isTransitioning) return;
           
           if (index < 0) index = slideCount - 1;
           if (index >= slideCount) index = 0;
           
           isTransitioning = true;
           currentSlide = index;
           $wrapper.css('transform', 'translateX(-' + (index * 100) + '%)');
           
           // 更新标题状态
           $titleItems.each(function(i) {
               var $item = $(this);
               var $text = $item.find('.title-text');
               var $indicator = $item.find('.title-indicator');
               
               if (i === index) {
                   $item.addClass('active');
                   $text.css('opacity', '1').css('font-weight', 'bold');
                   $indicator.css('background', '#ff6600');
               } else {
                   $item.removeClass('active');
                   $text.css('opacity', '0.7').css('font-weight', 'normal');
                   $indicator.css('background', 'transparent');
               }
           });
           
           setTimeout(function() {
               isTransitioning = false;
           }, 500);
       }
       
       // 下一张
       function nextSlide() {
           goToSlide(currentSlide + 1);
       }
       
       // 上一张
       function prevSlide() {
           goToSlide(currentSlide - 1);
       }
       
       // 自动播放
       function startAutoPlay() {
           autoPlayInterval = setInterval(nextSlide, 10000);
       }
       
       // 停止自动播放
       function stopAutoPlay() {
           clearInterval(autoPlayInterval);
       }
       
       // 绑定左右切换按钮事件(处理图片点击)
       $container.find('.carousel-next').click(function(e) {
           e.preventDefault();
           e.stopPropagation();
           stopAutoPlay();
           nextSlide();
           startAutoPlay();
       });
       
       $container.find('.carousel-prev').click(function(e) {
           e.preventDefault();
           e.stopPropagation();
           stopAutoPlay();
           prevSlide();
           startAutoPlay();
       });
       
       // 防止按钮内的图片链接跳转
       $container.find('.carousel-btn img, .carousel-btn a').click(function(e) {
           e.preventDefault();
           return false;
       });
       
       // 绑定标题点击事件
       $titleItems.click(function() {
           var slideIndex = parseInt($(this).attr('data-slide'));
           stopAutoPlay();
           goToSlide(slideIndex);
           startAutoPlay();
       });
       
       // 鼠标悬停在容器时暂停
       $container.hover(
           function() { stopAutoPlay(); },
           function() { startAutoPlay(); }
       );
       
       // 触摸滑动支持(移动设备)
       var touchStartX = 0;
       var touchEndX = 0;
       
       $container.on('touchstart', function(e) {
           touchStartX = e.originalEvent.changedTouches[0].screenX;
       });
       
       $container.on('touchend', function(e) {
           touchEndX = e.originalEvent.changedTouches[0].screenX;
           handleSwipe();
       });
       
       function handleSwipe() {
           if (touchEndX < touchStartX - 50) {
               stopAutoPlay();
               nextSlide();
               startAutoPlay();
           }
           if (touchEndX > touchStartX + 50) {
               stopAutoPlay();
               prevSlide();
               startAutoPlay();
           }
       }
       
       // 键盘控制
       $(document).keydown(function(e) {
           if ($container.is(':hover')) {
               if (e.keyCode === 37) { // 左箭头
                   stopAutoPlay();
                   prevSlide();
                   startAutoPlay();
               } else if (e.keyCode === 39) { // 右箭头
                   stopAutoPlay();
                   nextSlide();
                   startAutoPlay();
               }
           }
       });
       
       // 启动自动播放
       if (slideCount > 1) {
           startAutoPlay();
       }
   });

}); </script>