【问题标题】:Carousel slides incorrectly when swiping or when clicking the slider controls (next/prev)滑动或单击滑块控件时轮播不正确滑动(下一个/上一个)
【发布时间】:2023-04-01 11:57:02
【问题描述】:

我刚刚完成了一个我一直在做的轮播,它使用滑动/触摸,还使用 ​​prev/next 等控件来控制轮播。现在我有一个关于轮播行为的问题。基本上我试图让它一张一张地滑动。这是我一直在处理的代码示例。现在它似乎在滑动 2 或 3,具体取决于我放置了多少轮播。

我也有一个关于使它也响应的问题

function fCarousel() {
  // var activeSlide = 0;
  // $('.faculty-carousel').attr('data-slide', '0');

  var viewPortSize        = $(window).width(),
      facultyPanel = $('.faculty-carousel .faculty-items li'),
      profileCount = facultyPanel.length,
      activeSlide         = 0,
      carousel            = $('.faculty-carousel .faculty-items');

  $('.faculty-carousel').attr('data-slide', '0');

  //Set Panel Size based on viewport

  if (viewPortSize <= 1920 ) {
      var profilePanelSize = viewPortSize / 5
  }

  if (viewPortSize < 1024 ) {
      var profilePanelSize = viewPortSize / 4
  }

  if (viewPortSize < 768 ) {
      var profilePanelSize = viewPortSize / 3
  } 

  if (viewPortSize < 480 ) {
      var profilePanelSize = viewPortSize
  }

  carousel.outerWidth( profilePanelSize * profileCount );
  facultyPanel.outerWidth(profilePanelSize);
  carousel.css('transform', 'translateX(' + 0 + '% )');

  $('.prev').on('click', function(e) {
      event.stopPropagation();

    var carouselWrapper     = $(this).closest('.faculty-carousel'),
        facultyProfilePanel = carouselWrapper.find('.faculty-items li'),
        facultyProfileCount = facultyProfilePanel.length,
        viewPortSize        = $(window).width(),
        carousel = carouselWrapper.find('.faculty-items'),
        position            = 0,
        currentSlide        = parseInt(carouselWrapper.attr('data-slide'));

      // Check if data-slide attribute is greater than 0
      if (currentSlide > 0) {
          // Decremement current slide
          currentSlide--;
          // Assign CSS position to clicked slider
          var transformPercentage = -1 * currentSlide / facultyProfileCount * 100;
          carousel.css('transform', 'translateX(' + transformPercentage + '% )');
          // Update data-slide attribute
          carouselWrapper.attr('data-slide', currentSlide);
          activeSlide = currentSlide;
      }
  });

  $('.next').on('click', function(e) {
      event.stopPropagation();
      // store variable relevent to clicked slider

    var carouselWrapper     = $(this).closest('.faculty-carousel'),
        facultyProfilePanel = carouselWrapper.find('.faculty-items li'),
        facultyProfileCount = facultyProfilePanel.length,
        viewPortSize   = $(window).width(),
        carousel = carouselWrapper.find('.faculty-items'),
        position = 0,
        currentSlide = parseInt(carouselWrapper.attr('data-slide'));

      // Check if dataslide is less than the total slides
      if (currentSlide < facultyProfileCount - 1) {
          // Increment current slide
          currentSlide++;
          // Assign CSS position to clicked slider
          var transformPercentage = -1 * currentSlide / facultyProfileCount * 100;
          carousel.css('transform', 'translateX(' + transformPercentage + '% )');
          // Update data-slide attribute
          carouselWrapper.attr('data-slide', currentSlide);
          activeSlide = currentSlide;
      }
  })

    $('.faculty-carousel .faculty-items').each(function() {

        // create a simple instance
        // by default, it only adds horizontal recognizers

        var direction;
        var touchSlider = this;
        var mc = new Hammer.Manager(this),
            itemLength = $(this).find('li').length,
            count = 0,
            slide = $(this),
            timer;

        var sliderWrapper = slide,
            slideItems = sliderWrapper.find('li'),
            //slider = sliderWrapper.find('li'),
            totalPanels = slideItems.length,
            currentSlide = parseInt(sliderWrapper.attr('data-slide'));

        // mc.on("panleft panright", function(ev) {
        //   direction = ev.type;
        // });

        mc.add(new Hammer.Pan({
            threshold: 0,
            pointers: 0
        }))
        mc.on('pan', function(e) {
            var percentage = 100 / totalPanels * e.deltaX / window.innerWidth;
            var transformPercentage = percentage - 100 / totalPanels * activeSlide;
            touchSlider.style.transform = 'translateX( ' + transformPercentage + '% )';
            var sliderWrapper = $(e.target).closest('.faculty-carousel')


            if (e.isFinal) { // NEW: this only runs on event end

                var newSlide = activeSlide;
                if (percentage < 0)
                    newSlide = activeSlide + 1;
                else if (percentage > 0)
                    newSlide = activeSlide - 1;
                goToSlide(newSlide, sliderWrapper);
            }
        });


        var goToSlide = function(number, sliderWrapper) {
            if (number < 0)
                activeSlide = 0;
            else if (number > totalPanels - 1)
                activeSlide = totalPanels - 1
            else
                activeSlide = number;

            sliderWrapper.attr('data-slide', activeSlide);

            touchSlider.classList.add('slide-animation');
            var percentage = -(100 / totalPanels) * activeSlide;
            touchSlider.style.transform = 'translateX( ' + percentage + '% )';
            timer = setTimeout(function() {
                touchSlider.classList.remove('slide-animation');
            }, 400);

        };
    });

}

$(document).ready(function() {
  fCarousel();
})

$(window).on('resize', function(){
  fCarousel();
})
/* http://meyerweb.com/eric/tools/css/reset/ 
   v2.0 | 20110126
   License: none (public domain)
*/

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, 
figure, figcaption, footer, header, hgroup, 
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section {
  display: block;
}
body {
  line-height: 1;
}
ol, ul {
  list-style: none;
}
blockquote, q {
  quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
  content: '';
  content: none;
}
table {
  border-collapse: collapse;
  border-spacing: 0;
}
.faculty-items li {
    height : 100px;
}
.faculty-items li:nth-child(odd) {
    background-color : grey;
}
.faculty-items li:nth-child(even) {
    background-color : aqua
}
.faculty-items {
    overflow   : hidden;
    position   : relative;
    right      : 0;
    display : flex;
    -webkit-transition: transform 0.3s linear;
}
.faculty-carousel .controls {
    display : block;
}
<!doctype html>
<html>
<head>
<title>Carousel</title>
<link rel="stylesheet" href="style.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
</head>
<body>
  <div class="faculty-carousel">
    <ul class="faculty-items">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
        <li>Item 4</li>
        <li>Item 5</li>
        <li>Item 6</li>
    </ul>

    <div class="controls">
      <div class="prev">
        prev
      </div>

      <div class="next">
        next
      </div>
    </div>
  </div>


  <div class="faculty-carousel">
    <ul class="faculty-items">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
        <li>Item 4</li>
        <li>Item 5</li>
        <li>Item 6</li>
    </ul>

    <div class="controls">
      <div class="prev">
        prev
      </div>

      <div class="next">
        next
      </div>
    </div>
  </div>

  <div class="faculty-carousel">
    <ul class="faculty-items">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
        <li>Item 4</li>
        <li>Item 5</li>
        <li>Item 6</li>
    </ul>

    <div class="controls">
      <div class="prev">
        prev
      </div>

      <div class="next">
        next
      </div>
    </div>
  </div>
</body>
</html>

【问题讨论】:

  • 为什么不直接使用已经存在的,而不是再次发明轮子呢?你的滑块看起来很光滑:kenwheeler.github.io/slick
  • @Red 这个练习的目的是让我可以学习如何构建 UI 组件,如滑块和轮播,而不是使用第三方资源。

标签: javascript jquery css hammer.js


【解决方案1】:

好的,我在这里的第一个答案是匆忙完成的,但我相信我对大多数现代轮播的功能有一个清晰的 JavaScript 表示,尽管如果您选择使用它,其余的取决于您。

这里很好地解释了 JavaScript 方面

// Index all Carousel
for (var i = 0; i < document.getElementsByClassName("carousel").length; i++) {
    // Create a container for all the slides
    document.getElementsByClassName("carousel")[i].innerHTML = (
        '<div class="slides-container">' +
            document.getElementsByClassName("carousel")[i].innerHTML +
        '</div>'
    );

    // If the Carousel is automated
    if (document.getElementsByClassName("carousel")[i].getAttribute("data-auto")) {
        // Remove all white-space in the Carousel's "data-auto" attribute.
        document.getElementsByClassName("carousel")[i].setAttribute("data-auto", document.getElementsByClassName("carousel")[i].getAttribute("data-auto").replace(/ /g, ""));

        // Set the Carousel direction
        document.getElementsByClassName("carousel")[i]._direction = String(document.getElementsByClassName("carousel")[i].getAttribute("data-auto").slice(0, document.getElementsByClassName("carousel")[i].getAttribute("data-auto").indexOf("_")));

        // Set the Carousel interval
        document.getElementsByClassName("carousel")[i]._interval = (parseFloat(document.getElementsByClassName("carousel")[i].getAttribute("data-auto").slice(document.getElementsByClassName("carousel")[i].getAttribute("data-auto").indexOf("_")).replace("_", "")) * 1000)
    };

    // Index all Carousel slides
    for (var j = 0; j < document.getElementsByClassName("carousel")[i].querySelector(".slides-container").children.length; j++)
        // Hide them
        document.getElementsByClassName("carousel")[i].querySelector(".slides-container").children[j].hidden = true;

        // Show the first one or the specified slide
        document.getElementsByClassName("carousel")[i].querySelector(".slides-container").children[(parseInt(document.getElementsByClassName("carousel")[i].getAttribute("data-active")) || 0)].hidden = false;

    // Carousel Next
    document.getElementsByClassName("carousel")[i]._next = function() {
        // Index all Carousel Slides
        for (var j = 0; j < this.querySelector(".slides-container").children.length; j++)
            // Show the next slide in the set
            if (this.querySelector(".slides-container").children[j].hidden == false) {
                this.querySelector(".slides-container").children[j].hidden = true;
                (this.querySelector(".slides-container").children[j].nextElementSibling || this.querySelector(".slides-container").children[0]).hidden = false;

                break
            }
    };

    // Carousel Previous
    document.getElementsByClassName("carousel")[i]._prev = function() {
        // Index all Carousel Slides
        for (var j = 0; j < this.querySelector(".slides-container").children.length; j++)
            // Show the previous slide in the set
            if (this.querySelector(".slides-container").children[j].hidden == false) {
                this.querySelector(".slides-container").children[j].hidden = true;
                (this.querySelector(".slides-container").children[j].previousElementSibling || this.querySelector(".slides-container").children[this.querySelector(".slides-container").children.length - 1]).hidden = false;

                break
            }
    };

    // Carousel Toggle
    document.getElementsByClassName("carousel")[i]._toggle = function(slideIndex) {
        // Index all Carousel Slides
        for (var j = 0; j < this.querySelector(".slides-container").children.length; j++)
            // Hide them
            this.querySelector(".slides-container").children[j].hidden = true;

        // Show the specified slide
        (this.querySelector(".slides-container").children[slideIndex] || document.createElement("div")).hidden = false
    };

    // If the Carousel Interval is a Number
    if (typeof document.getElementsByClassName("carousel")[i]._interval == "number") {
        // Index
        var index = i;

        // Set an interval to automate the Carousel
        setInterval(function() {
            // If the Carousel direction is right
            if (document.getElementsByClassName("carousel")[index]._direction == "right")
                document.getElementsByClassName("carousel")[index]._next();

            // If the Carousel direction is left
            else if (document.getElementsByClassName("carousel")[index]._direction == "left")
                document.getElementsByClassName("carousel")[index]._prev()
        }, document.getElementsByClassName("carousel")[i]._interval)
    }

    // If the Carousel has buttons
    if (document.getElementsByClassName("carousel")[i].hasAttribute("data-buttons"))
        // Make the Buttons Container
        document.getElementsByClassName("carousel")[i].innerHTML += (
            '<div class="buttons-container">' +
                '<button onclick="this.parentNode.parentNode._prev()"> Previous </button>' +
                '<button onclick="this.parentNode.parentNode._next()"> Next </button>' +
            '</div>'
        )

    // If the Carousel has indicators
    if (document.getElementsByClassName("carousel")[i].hasAttribute("data-indicators"))
        // Make the Indicators Container
        document.getElementsByClassName("carousel")[i].innerHTML += (
            '<div class="indicators-container">' +
                // Place as many checkboxes for as many slides there are
                (function() {
                    var indicators = "";

                    for (var k = 0; k < document.getElementsByClassName("carousel")[i].querySelector(".slides-container").children.length; k++)
                        indicators += (
                            '<input class="indicator-' + k + '" onclick="this.parentNode.parentNode._toggle(this.getAttribute(\'class\')[this.getAttribute(\'class\').length - 1])" type="checkbox">'
                        );

                    return indicators
                })() +
            '</div>'
        );

    // Add a click event to the Carousel
    document.getElementsByClassName("carousel")[i].addEventListener("click", function() {
        // Index all Carousel
        for (var j = 0; j < document.getElementsByClassName("carousel").length; j++)
            // If the Carousel indexed is not the target Carousel
            if (document.getElementsByClassName("carousel")[j] != this)
                // Blur it
                document.getElementsByClassName("carousel")[j].removeAttribute("data-focus");

            else
                // 'Focus' it
                document.getElementsByClassName("carousel")[j].setAttribute("data-focus", "")

        // If the mouse click is to the left of the carousel
        if (event.clientX < (this.getBoundingClientRect().left + (this.getBoundingClientRect().width / 2)))
            this._prev();

        // If the mouse click is to the right of the carousel
        else if ((event.clientX > (this.getBoundingClientRect().left + (this.getBoundingClientRect().width / 2))))
            this._next()
    })
};

// Attach an event to the <body>.
document.body.addEventListener("keydown", function() {
    switch (event.code) {
        // If the left arrow key is pressed
        case "ArrowLeft":
            document.querySelector(".carousel[data-focus")._prev();
            break;

        // If the right arrow key is pressed
        case "ArrowRight":
            document.querySelector(".carousel[data-focus")._next();
            break;
    }
})

在 Carousel 的这部分代码中,.hidden 属性可以替换为其他任何内容,但它提供了幻灯片如何通过活动和非活动状态的基本概念。 至于HTML部分

<html>
    <body>
        <div class="carousel" data-active="1" data-auto="right_1" data-buttons data-indicators style="height: 300px">
            <div style="background: #F00; color: #FFF; font-size: 50px; height: 100%; line-height: 300px; text-align: center"> R </div>
            <div style="background: #0F0; color: #FFF; font-size: 50px; height: 100%; line-height: 300px; text-align: center"> G </div>
            <div style="background: #00F; color: #FFF; font-size: 50px; height: 100%; line-height: 300px; text-align: center"> B </div>
        </div>

        <!-- The JS script for the Carousel -->
        <script src="carousel.js"> </script>
    </body>
</html>

一切都已简化: classcarousel 制作一个新的轮播, data-active 属性来说明哪张幻灯片处于活动状态(从 0 开始), data-auto 属性指定轮播是否是自动化的(right_ 代表自动化方向,_1 代表间隔时间), data-buttons 属性(如果需要按钮), data-indicators 如果需要轮播指示器并且 幻灯片作为 Carousel 的子项。

是的,这几乎是构建简单轮播所需的 HTML/JS 代码。

如果您正在寻找 JavaScript 世界中发生的任何令人兴奋的事情,我正在开发一个我认为您可能会感兴趣的库:https://github.com/LapysDev/LapysJS

【讨论】:

    【解决方案2】:

    tru 使用 Slick 画廊,最好使用任何画廊 http://kenwheeler.github.io/slick/

    【讨论】:

      【解决方案3】:

      以下内容应该可以解决您的幻灯片问题。我在 CSS 和 JS 中添加了一些代码,以确保幻灯片将在一张幻灯片上移动,并且还可以在较小的屏幕分辨率上工作。

      JS:

      CSS:

      HTML:我保持不变,所以只需使用与您相同的 HTML。最好的问候。

      【讨论】:

        【解决方案4】:

        在元素集合中设置/获取值时,最好使用use .map()。这是 50 行中的答案(view on CodePen):

        $(".faculty-carousel").map(function() {
          // Use that to refer to the child nodes of each carousel object instance
          var that = $(this),
            slides = that.find(".faculty-items li"),
            carousel = that.find(".faculty-items"),
            prevBtn = that.find(".prev"),
            nextBtn = that.find(".next"),
            slideLen = slides.length,
            slideCount = slideLen - 1;
        
          // Set reference point for carousel movements. The .is-active class will always 
          // be applied to the activeSlide, providing a reliable method for maintaining 
          // the carousel's state.
          slides.first().addClass("is-active");
        
          // Shift in response to user click. Accepts optional direction argument
          var shiftCarousel = function(direction) {
            var target = that.find(".is-active");
            var currentSlide = target.attr("data-slide");
            if (direction === "left" && currentSlide > 0) {
              currentSlide--;
              target.removeClass("is-active").prev().addClass("is-active");
            }
            if (direction === "right" && currentSlide < slideCount) {
              currentSlide++;
              target.removeClass("is-active").next().addClass("is-active");
            }
            var transformPercentage = -1 * currentSlide / slideLen * 100;
            carousel.css("transform", "translateX(" + transformPercentage + "% )");
          };
        
          var x = 0;
        
          // Get position of each slide and store it in an HTML attribute
          slides.each(function() {
            $(this).attr("data-slide", "" + x++ + "");
            $(this).click(function() {
              $(this).addClass("is-active").siblings().removeClass("is-active");
        
              // Invoke shiftCarousel() without a parameter
              shiftCarousel();
            });
          });
        
          // Invoke shiftCarousel() with a parameter
          prevBtn.on("click", function() {
            shiftCarousel("left");
          });
          nextBtn.on("click", function() {
            shiftCarousel("right");
          });
        
          // to manage mobile events, you can reference events via Hammer API 
          // or JavaScript's built-in touchstart, touchcancel  etc. events i.e.
          // prevBtn.on('touchstart', function() {
            // do something
          // });
        });
        

        这里最好坚持使用 jQuery。 Oluwafunmito 的解决方案使用innerHTML,如果使用 vanilla JS,这是唯一实用的技术。但是,innerHTML 可以inadvertently expose your website visitors 受到 XSS 攻击,应尽可能避免。

        【讨论】:

          【解决方案5】:

          您可以使用swiper。最现代的移动触摸滑块,具有硬件加速过渡和惊人的原生行为。

          【讨论】:

            【解决方案6】:

            我可以使用引导程序和 JavaScript 为您提供一个功能齐全的轮播代码,而不是遍历您的整个代码。也许这会提示您的程序缺少哪些地方,并有助于纠正您的代码。

            <div id="mycarousel" class="carousel slide" data-interval="3000" data-ride="carousel">
                        <!-- Indicators -->
            <ol class="carousel-indicators">
                <li data-target="#mycarousel" data-slide-to="0" class="active"></li>
                <li data-target="#mycarousel" data-slide-to="1"></li>
                <li data-target="#mycarousel" data-slide-to="2"></li>
            </ol>
                        <!-- Wrapper for slides -->
            <div class="carousel-inner" role="listbox">
                <div class="item active">
                    <img class="img-responsive"
                     src="img/uthappizza.png" alt="Uthappizza">
                    <div class="carousel-caption">
                    <h2>Uthappizza  <span class="label label-danger">Hot</span> <span class="badge">$4.99</span></h2>
                    <p>A unique combination of Indian Uthappam (pancake) and
                      Italian pizza, topped with Cerignola olives, ripe vine
                      cherry tomatoes, Vidalia onion, Guntur chillies and
                      Buffalo Paneer.</p>
                    <p><a class="btn btn-primary btn-xs" href="#">More &raquo;</a></p>
                    </div>
                </div>
                <div class="item">
                  <img class="media-object img-thumbnail"
                   src="img/buffet.png" alt="Buffet">
                    <div class="carousel-caption">
                      <h2>Weekend Grand Buffet <span class="label label-danger">New</span> </h2>
                      <p>Featuring mouthwatering combinations with a choice of five different salads,
                         six enticing appetizers, six main entrees and five choicest desserts.
                          Free flowing bubbly and soft drinks. All for just $19.99 per person</p>
                      <p><a class="btn btn-primary btn-xs" href="#">More &raquo;</a></p>
                      </div>
                </div>
                <div class="item">
                  <img class="media-object img-thumbnail"
                   src="img/alberto.png" alt="Alberto Somayya">
                    <div class="carousel-caption">
                      <h2 >Alberto Somayya</h2>
                      <h4>Executive Chef</h4>
                      <p>Award winning three-star Michelin chef with wide
                       International experience having worked closely with
                       whos-who in the culinary world, he specializes in
                        creating mouthwatering Indo-Italian fusion experiences.
                       </p>
                       <p><a class="btn btn-primary btn-xs" href="#">More &raquo;</a></p>
            
                    </div>
                </div>
                <!-- Controls -->
            <a class="left carousel-control" href="#mycarousel" role="button" data-slide="prev">
                <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
                <span class="sr-only">Previous</span>
            </a>
            <a class="right carousel-control" href="#mycarousel" role="button" data-slide="next">
                <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
                <span class="sr-only">Next</span>
            
            </a>
            <div class="btn-group" id="carouselButtons">
                <button class="btn btn-danger btn-sm" id="carousel-pause">
                  <span class="fa fa-pause" aria-hidden="true"></span>
                </button>
                <button class="btn btn-danger btn-sm" id="carousel-play">
                  <span class="fa fa-play" aria-hidden="true"></span>
                </button>
            </div>
            
            </div>
                      </div>
            

            JavaScript

            <script>
                $('.carousel').carousel('pause')
            </script>
            <script>
                $(".btn-group > .btn").click(function(){
                $(this).addClass("active").siblings().removeClass("active");
                });
            </script>
            <script>
            $(document).ready(function(){
                //$("#mycarousel").carousel( { interval: 2000 } );
                              $("#carousel-pause").click(function(){
                    $("#mycarousel").carousel('pause');
                });
                            $("#carousel-play").click(function(){
                    $("#mycarousel").carousel('cycle');
                });
              });
            </script>
            

            学分:课程

            【讨论】:

              【解决方案7】:

              您在所有轮播的所有幻灯片上使用 .each,为每张幻灯片设置平移事件和动画。尝试只在$('.faculty-carousel').each上绑定你的函数(和包含的pan)

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2013-12-21
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-05-17
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多