Widget:Carousel

From ChaosZeroNightmareWiki
Revision as of 16:38, 17 April 2026 by 律Rhyme (talk | contribs) (Created page with "<div id="carousel-container"></div> <style> ===== 轮播容器 =====: #carousel-container { position: relative; width: 100%; max-width: 960px; margin: 0 auto; overflow: hidden; border-radius: 8px; background: #1a1a1a; } #carousel-container .carousel-wrapper { position: relative; width: 100%; padding-top: 56.25%; 16:9: } #carousel-container .carousel-slide { position: absolute; top: 0; left: 0; width: 10...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

<style> /* ===== 轮播容器 ===== */

  1. carousel-container {
   position: relative;
   width: 100%;
   max-width: 960px;
   margin: 0 auto;
   overflow: hidden;
   border-radius: 8px;
   background: #1a1a1a;

}

  1. carousel-container .carousel-wrapper {
   position: relative;
   width: 100%;
   padding-top: 56.25%; /* 16:9 */

}

  1. carousel-container .carousel-slide {
   position: absolute;
   top: 0;
   left: 0;
   width: 100%;
   height: 100%;
   opacity: 0;
   transition: opacity 0.6s ease-in-out;
   cursor: pointer;
   display: block;
   text-decoration: none;
   color: inherit;

}

  1. carousel-container .carousel-slide.active {
   opacity: 1;
   z-index: 1;

}

  1. carousel-container .carousel-slide .slide-bg {
   position: absolute;
   top: 0;
   left: 0;
   width: 100%;
   height: 100%;
   background-size: cover;
   background-position: center;
   background-repeat: no-repeat;

}

  1. carousel-container .carousel-slide .slide-overlay {
   position: absolute;
   top: 0;
   left: 0;
   width: 100%;
   height: 100%;
   background: linear-gradient(
       to top,
       rgba(0, 0, 0, 0.85) 0%,
       rgba(0, 0, 0, 0.5) 40%,
       rgba(0, 0, 0, 0.2) 70%,
       rgba(0, 0, 0, 0.1) 100%
   );

}

  1. carousel-container .slide-content {
   position: absolute;
   bottom: 0;
   left: 0;
   right: 0;
   padding: 24px 32px;
   z-index: 2;

}

  1. carousel-container .slide-category {
   display: inline-block;
   border: 1.5px solid #ffffff;
   color: #ffffff;
   font-size: 11px;
   font-weight: 700;
   letter-spacing: 1.5px;
   padding: 3px 10px;
   margin-bottom: 16px;
   text-transform: uppercase;
   background: transparent;

}

  1. carousel-container .slide-title {
   font-size: 24px;
   font-weight: 800;
   color: #ffffff;
   margin: 0 0 8px 0;
   line-height: 1.3;

}

  1. carousel-container .slide-desc {
   font-size: 14px;
   color: rgba(255, 255, 255, 0.85);
   margin: 0 0 16px 0;
   font-weight: 500;
   line-height: 1.5;

}

/* ===== 指示器 ===== */

  1. carousel-container .carousel-indicators {
   display: flex;
   gap: 6px;
   align-items: center;

}

  1. carousel-container .carousel-indicator {
   width: 24px;
   height: 3px;
   background: rgba(255, 255, 255, 0.35);
   border: none;
   border-radius: 2px;
   cursor: pointer;
   padding: 0;
   transition: all 0.3s ease;
   position: relative;
   overflow: hidden;

}

  1. carousel-container .carousel-indicator::after {
   content: ;
   position: absolute;
   top: 0;
   left: 0;
   height: 100%;
   width: 0%;
   background: #fb5711;
   border-radius: 2px;
   transition: none;

}

  1. carousel-container .carousel-indicator.active::after {
   width: 100%;
   transition: width 5s linear;

}

  1. carousel-container .carousel-indicator.active {
   width: 32px;
   background: rgba(255, 255, 255, 0.2);

}

  1. carousel-container .carousel-indicator.visited {
   background: #fb5711;

}

  1. carousel-container .carousel-indicator.visited::after {
   width: 100%;
   transition: none;

}

/* ===== 左右箭头 ===== */

  1. carousel-container .carousel-arrow {
   position: absolute;
   top: 50%;
   transform: translateY(-50%);
   z-index: 10;
   background: rgba(0, 0, 0, 0.45);
   border: none;
   color: #fff;
   width: 40px;
   height: 40px;
   border-radius: 50%;
   cursor: pointer;
   font-size: 18px;
   display: flex;
   align-items: center;
   justify-content: center;
   opacity: 0;
   transition: opacity 0.3s ease, background 0.3s ease;

}

  1. carousel-container:hover .carousel-arrow {
   opacity: 1;

}

  1. carousel-container .carousel-arrow:hover {
   background: #fb5711;

}

  1. carousel-container .carousel-arrow-left {
   left: 12px;

}

  1. carousel-container .carousel-arrow-right {
   right: 12px;

}

/* ===== 单张时隐藏控件 ===== */

  1. carousel-container.single-slide .carousel-arrow,
  2. carousel-container.single-slide .carousel-indicators {
   display: none !important;

}

/* ===== 响应式 ===== */ @media (max-width: 600px) {

   #carousel-container .slide-content {
       padding: 16px 20px;
   }
   #carousel-container .slide-title {
       font-size: 18px;
   }
   #carousel-container .slide-desc {
       font-size: 12px;
   }
   #carousel-container .carousel-arrow {
       width: 32px;
       height: 32px;
       font-size: 14px;
   }

} </style>

<script> (function() {

   function initCarousel() {
       var dataEl = document.getElementById('carousel-data');
       var container = document.getElementById('carousel-container');
       if (!dataEl || !container) return;
       var count = parseInt(dataEl.getAttribute('data-count')) || 1;
       if (count > 4) count = 4;
       var slides = [];
       for (var i = 1; i <= count; i++) {
           slides.push({
               image: dataEl.getAttribute('data-banner' + i) || ,
               category: dataEl.getAttribute('data-banner' + i + '-category') || ,
               title: dataEl.getAttribute('data-banner' + i + '-title') || ,
               desc: dataEl.getAttribute('data-banner' + i + '-desc') || ,
               jump: dataEl.getAttribute('data-banner' + i + '-jump') || 
           });
       }
       if (slides.length === 0) return;
       if (slides.length === 1) container.classList.add('single-slide');
       // Build HTML

var html = '

';

       container.innerHTML = html;
       if (slides.length <= 1) return;
       // Carousel logic
       var current = 0;
       var slideEls = container.querySelectorAll('.carousel-slide');
       var allIndicators = container.querySelectorAll('.carousel-indicator');
       var timer = null;
       var INTERVAL = 5000;
       function getIndicatorsForSlide(idx) {
           // Each slide has its own set of indicators; get them
           var sets = [];
           for (var s = 0; s < slideEls.length; s++) {
               var inds = slideEls[s].querySelectorAll('.carousel-indicator');
               sets.push(inds);
           }
           return sets;
       }
       function goTo(idx, fromAuto) {
           if (idx === current) return;
           slideEls[current].classList.remove('active');
           current = idx;
           slideEls[current].classList.add('active');
           updateIndicators();
           resetTimer();
       }
       function updateIndicators() {
           // Update indicators in ALL slides (so the active slide shows correct state)
           var allSets = container.querySelectorAll('.carousel-slide');
           for (var s = 0; s < allSets.length; s++) {
               var inds = allSets[s].querySelectorAll('.carousel-indicator');
               for (var j = 0; j < inds.length; j++) {
                   inds[j].classList.remove('active', 'visited');
                   if (j < current) {
                       inds[j].classList.add('visited');
                   } else if (j === current) {
                       // Force reflow for animation restart
                       inds[j].classList.add('active');
                       void inds[j].offsetWidth;
                   }
               }
           }
           // Re-trigger the animation by removing and re-adding
           setTimeout(function() {
               var activeInds = container.querySelectorAll('.carousel-indicator.active');
               for (var k = 0; k < activeInds.length; k++) {
                   activeInds[k].classList.remove('active');
                   void activeInds[k].offsetWidth;
                   activeInds[k].classList.add('active');
               }
           }, 10);
       }
       function next() {
           goTo((current + 1) % slides.length);
       }
       function prev() {
           goTo((current - 1 + slides.length) % slides.length);
       }
       function resetTimer() {
           clearInterval(timer);
           timer = setInterval(next, INTERVAL);
       }
       // Arrow events
       container.querySelector('.carousel-arrow-left').addEventListener('click', function(e) {
           e.preventDefault();
           e.stopPropagation();
           prev();
       });
       container.querySelector('.carousel-arrow-right').addEventListener('click', function(e) {
           e.preventDefault();
           e.stopPropagation();
           next();
       });
       // Indicator events (delegate)
       container.addEventListener('click', function(e) {
           var btn = e.target.closest('.carousel-indicator');
           if (btn) {
               e.preventDefault();
               e.stopPropagation();
               var idx = parseInt(btn.getAttribute('data-index'));
               if (!isNaN(idx)) goTo(idx);
           }
       });
       // Pause on hover
       container.addEventListener('mouseenter', function() { clearInterval(timer); });
       container.addEventListener('mouseleave', function() { resetTimer(); });
       updateIndicators();
       resetTimer();
   }
   if (document.readyState === 'loading') {
       document.addEventListener('DOMContentLoaded', initCarousel);
   } else {
       initCarousel();
   }

})(); </script>