ホーム>source

更新: その解決 以下に投稿したのは十分ではありません。アクティブな弾丸を除くすべての弾丸を作るからですクリックに反応しない、 の代わりにそれらをキューに入れる、したがって改善の余地があります。


jQueryとCSSを使用して、カスタム画像カルーセルに取り組んでいます。私の目的はそれを本当に作ることです軽量 しかし、(ちょうど)十分な機能を備えています:「弾丸」、自動前進、応答性。

それは正常に動作しますが、修正できないバグを発見しました:2つの弾丸を連続してクリックすると-最初のトリガーによって遷移が終了する前に2番目をクリックする -トランジションは私が説明できない奇妙な方法で重なりますが、以下に表示されます:

var $elm = $('.slider'),
  $slidesContainer = $elm.find('.slider-container'),
  slides = $slidesContainer.children('a'),
  slidesCount = slides.length,
  slideHeight = $(slides[0]).find('img').outerHeight(false),
  animationspeed = 1500,
  animationInterval = 7000;
// Set (initial) z-index for each slide
var setZindex = function() {
  for (var i = 0; i < slidesCount; i++) {
    $(slides[i]).css('z-index', slidesCount - i);
  }
};
setZindex();
var displayImageBeforeClick = null;
var setActiveSlide = function() {
  $(slides).removeClass('active');
  $(slides[activeIdx]).addClass('active');
};
var advanceFunc = function() {
  if ($('.slider-nav li.activeSlide').index() + 1 != $('.slider-nav li').length) {
    $('.slider-nav li.activeSlide').next().find('a').trigger('click');
  } else {
    $('.slider-nav li:first').find('a').trigger('click');
  }
}
var autoAdvance = setInterval(advanceFunc, animationInterval);
//Set slide height
$(slides).css('height', slideHeight);
// Append bullets
if (slidesCount > 1) {
  /* Prepend the slider navigation to the slider
     if there are at least 2 slides */
  $elm.prepend('<ul class="slider-nav"></ul>');
  
  // make a bullet for each slide
  for (var i = 0; i < slidesCount; i++) {
    var bullets = '<li><a href="#">' + i + '</a></li>';
    if (i == 0) {
      // active bullet
      var bullets = '<li class="activeSlide"><a href="#">' + i + '</a></li>';
      // active slide
      $(slides[0]).addClass('active');
    }
    $('.slider-nav').append(bullets);
  }
};
var slideUpDown = function() {
  // set top property for all the slides
  $(slides).not(displayImageBeforeClick).css('top', slideHeight);
  // then animate to the next slide
  $(slides[activeIdx]).animate({
    'top': 0
  }, animationspeed);
  $(displayImageBeforeClick).animate({
    'top': "-100%"
  }, animationspeed);
};
$('.slider-nav a').on('click', function(event) {
  displayImageBeforeClick = $(".slider-container .active");
  activeIdx = $(this).text();
  if ($(slides[activeIdx]).hasClass("active")) {
    return false;
  }
  $('.slider-nav a').closest('li').removeClass('activeSlide');
  $(this).closest('li').addClass('activeSlide');
  // Reset autoadvance if user clicks bullet
  if (event.originalEvent !== undefined) {
    clearInterval(autoAdvance);
    autoAdvance = setInterval(advanceFunc, animationInterval);
  }
  setActiveSlide();
  slideUpDown();
});

body * {
  box-sizing: border-box;
}
.container {
  max-width: 1200px;
  margin: 0 auto;
}
.slider {
  width: 100%;
  height: 300px;
  position: relative;
  overflow: hidden;
}
.slider .slider-nav {
  text-align: center;
  position: absolute;
  padding: 0;
  margin: 0;
  left: 10px;
  right: 10px;
  bottom: 2px;
  z-index: 30;
}
.slider .slider-nav li {
  display: inline-block;
  width: 20px;
  height: 3px;
  margin: 0 1px;
  text-indent: -9999px;
  overflow: hidden;
  background-color: rgba(255, 255, 255, .5);
}
.slider .slider-nav a {
  display: block;
  height: 3px;
  line-height: 3px;
}
.slider .slider-nav li.activeSlide {
  background: #fff;
}
.slider .slider-nav li.activeSlide a {
  display: none;
}
.slider .slider-container {
  width: 100%;
  text-align: center;
}
.slider .slider-container a {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
}
.slider .slider-container img {
  transform: translateX(-50%);
  margin-left: 50%;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="container">
  <div class="slider slider-homepage">
    <div class="slider-container">
      <a href="#">
        <img src="https://picsum.photos/1200/300/?gravity=east" alt="">
      </a>
      <a href="#">
        <img src="https://picsum.photos/1200/300/?gravity=south" alt="">
      </a>
      <a href="#">
        <img src="https://picsum.photos/1200/300/?gravity=west" alt="">
      </a>
    </div>
  </div>
</div>

より良い用語がないため、イベントの混雑(オーバーラップ)と呼ばれるこの現象をどのように防ぐことができますか?

あなたの答え
  • 解決した方法 # 1

    jQuery遅延オブジェクトとPromiseを使用して、アニメーションをチェーンできます。簡単に実行できるクラスを次に示します。

    var Queue = function() {
        var lastPromise = null;
        this.add = function(callable) {
            var methodDeferred = $.Deferred();
            var queueDeferred = this.setup();
            // execute next queue method
            queueDeferred.done(function() {
                // call actual method and wrap output in deferred
                callable().then(methodDeferred.resolve)
            });
            lastPromise = methodDeferred.promise();
        };
        this.setup = function() {
            var queueDeferred = $.Deferred();
            // when the previous method returns, resolve this one
            $.when(lastPromise).always(function() {
                queueDeferred.resolve();
            });
            return queueDeferred.promise();
        }
    };
    
    

    フィドルは、アニメーションがキューに入れられた状態です。

    PS:ボタンのサイズを大きくしてクリックしやすくしました

    var $elm = $('.slider'),
      $slidesContainer = $elm.find('.slider-container'),
      slides = $slidesContainer.children('a'),
      slidesCount = slides.length,
      slideHeight = $(slides[0]).find('img').outerHeight(false),
      animationspeed = 1500,
      animationInterval = 7000;
    // Set (initial) z-index for each slide
    var setZindex = function() {
      for (var i = 0; i < slidesCount; i++) {
        $(slides[i]).css('z-index', slidesCount - i);
      }
    };
    setZindex();
    var setActiveSlide = function() {
      $(slides).removeClass('active');
      $(slides[activeIdx]).addClass('active');
    };
    var advanceFunc = function() {
      if ($('.slider-nav li.activeSlide').index() + 1 != $('.slider-nav li').length) {
        $('.slider-nav li.activeSlide').next().find('a').trigger('click');
      } else {
        $('.slider-nav li:first').find('a').trigger('click');
      }
    }
    var autoAdvance = setInterval(advanceFunc, animationInterval);
    //Set slide height
    $(slides).css('height', slideHeight);
    // Append bullets
    if (slidesCount > 1) {
      /* Prepend the slider navigation to the slider
         if there are at least 2 slides */
      $elm.prepend('<ul class="slider-nav"></ul>');
      
      // make a bullet for each slide
      for (var i = 0; i < slidesCount; i++) {
        var bullets = '<li><a href="#">' + i + '</a></li>';
        if (i == 0) {
          // active bullet
          var bullets = '<li class="activeSlide"><a href="#">' + i + '</a></li>';
          // active slide
          $(slides[0]).addClass('active');
        }
        $('.slider-nav').append(bullets);
      }
    };
    var Queue = function() {
        var lastPromise = null;
        this.add = function(callable) {
            var methodDeferred = $.Deferred();
            var queueDeferred = this.setup();
            // execute next queue method
            queueDeferred.done(function() {
                // call actual method and wrap output in deferred
                callable().then(methodDeferred.resolve)
            });
            lastPromise = methodDeferred.promise();
        };
        this.setup = function() {
            var queueDeferred = $.Deferred();
            // when the previous method returns, resolve this one
            $.when(lastPromise).always(function() {
                queueDeferred.resolve();
            });
            return queueDeferred.promise();
        }
    };
    var queue = new Queue();
    var slideUpDown = function(previousIdx, activeIdx) {
      queue.add(function() {
        return new Promise(function(resolve, reject) {
          // set top property for all the slides
          $(slides).not(slides[previousIdx]).css('top', slideHeight);
          // then animate to the next slide
          $(slides[activeIdx]).animate({
            'top': 0
          }, animationspeed);
          $(slides[previousIdx]).animate({
            'top': "-100%"
          }, animationspeed, 'swing', resolve);
        })
      })
    };
    var previousIdx = '0' // First slide
    $('.slider-nav a').on('click', function(event) {
      activeIdx = $(this).text();
      
      // Disable clicling on an active item
      if ($(slides[activeIdx]).hasClass("active")) {
        return false;
      }
      $('.slider-nav a').closest('li').removeClass('activeSlide');
      $(this).closest('li').addClass('activeSlide');
      // Reset autoadvance if user clicks bullet
      if (event.originalEvent !== undefined) {
        clearInterval(autoAdvance);
        autoAdvance = setInterval(advanceFunc, animationInterval);
      }
      setActiveSlide();
      slideUpDown(previousIdx, activeIdx);
    	previousIdx = activeIdx
    });
    
    
    body * {
      box-sizing: border-box;
    }
    .container {
      max-width: 1200px;
      margin: 0 auto;
    }
    .slider {
      width: 100%;
      height: 300px;
      position: relative;
      overflow: hidden;
    }
    .slider .slider-nav {
      text-align: center;
      position: absolute;
      padding: 0;
      margin: 0;
      left: 10px;
      right: 10px;
      bottom: 2px;
      z-index: 30;
    }
    .slider .slider-nav li {
      display: inline-block;
      width: 20px;
      height: 6px;
      margin: 0 1px;
      text-indent: -9999px;
      overflow: hidden;
      background-color: rgba(255, 255, 255, .5);
    }
    .slider .slider-nav a {
      display: block;
      height: 6px;
      line-height: 3px;
    }
    .slider .slider-nav li.activeSlide {
      background: #fff;
    }
    .slider .slider-nav li.activeSlide a {
      display: none;
    }
    .slider .slider-container {
      width: 100%;
      text-align: center;
    }
    .slider .slider-container a {
      display: block;
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
    }
    .slider .slider-container img {
      transform: translateX(-50%);
      margin-left: 50%;
    }
    
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <div class="container">
      <div class="slider slider-homepage">
        <div class="slider-container">
          <a href="#">
            <img src="https://picsum.photos/1200/300/?gravity=east" alt="">
          </a>
          <a href="#">
            <img src="https://picsum.photos/1200/300/?gravity=south" alt="">
          </a>
          <a href="#">
            <img src="https://picsum.photos/1200/300/?gravity=west" alt="">
          </a>
        </div>
      </div>
    </div>
    
    

  • 解決した方法 # 2

    アニメーションが終了するのを待ってから別のアニメーションを開始するという、可能な修正方法を次に示します。

    var $elm = $('.slider'),
        $slidesContainer = $elm.find('.slider-container'),
        slides = $slidesContainer.children('a'),
        slidesCount = slides.length,
        slideHeight = $(slides[0]).find('img').outerHeight(false),
        animationspeed = 1500,
        animationInterval = 7000;
    // Set (initial) z-index for each slide
    var setZindex = function() {
        for (var i = 0; i < slidesCount; i++) {
            $(slides[i]).css('z-index', slidesCount - i);
        }
    };
    setZindex();
    var displayImageBeforeClick = null;
    var setActiveSlide = function() {
        $(slides).removeClass('active');
        $(slides[activeIdx]).addClass('active');
    };
    var advanceFunc = function() {
        if ($('.slider-nav li.activeSlide').index() + 1 != $('.slider-nav li').length) {
            $('.slider-nav li.activeSlide').next().find('a').trigger('click');
        } else {
            $('.slider-nav li:first').find('a').trigger('click');
        }
    }
    var autoAdvance = setInterval(advanceFunc, animationInterval);
    //Set slide height
    $(slides).css('height', slideHeight);
    // Append bullets
    if (slidesCount > 1) {
      /* Prepend the slider navigation to the slider
         if there are at least 2 slides */
      $elm.prepend('<ul class="slider-nav"></ul>');
      
      // make a bullet for each slide
      for (var i = 0; i < slidesCount; i++) {
        var bullets = '<li><a href="#">' + i + '</a></li>';
        if (i == 0) {
          // active bullet
          var bullets = '<li class="activeSlide"><a href="#">' + i + '</a></li>';
          // active slide
          $(slides[0]).addClass('active');
        }
        $('.slider-nav').append(bullets);
      }
    };
    var animationStart = false;
    var slideUpDown = function() {
        animationStart = true;
        // set top property for all the slides
        $(slides).not(displayImageBeforeClick).css('top', slideHeight);
        // then animate to the next slide
        $(slides[activeIdx]).animate({
            'top': 0
        }, animationspeed, function() {
            animationStart = false;
        });
        $(displayImageBeforeClick).animate({
            'top': "-100%"
        }, animationspeed, function() {
            animationStart = false;
        });
    };
    $('.slider-nav a').on('click', function(event) {
        if (animationStart) {
            return false;
        }
        displayImageBeforeClick = $(".slider-container .active");
        activeIdx = $(this).text();
        if ($(slides[activeIdx]).hasClass("active")) {
            return false;
        }
        $('.slider-nav a').closest('li').removeClass('activeSlide');
        $(this).closest('li').addClass('activeSlide');
        // Reset autoadvance if user clicks bullet
        if (event.originalEvent !== undefined) {
            clearInterval(autoAdvance);
            autoAdvance = setInterval(advanceFunc, animationInterval);
        }
        setActiveSlide();
        slideUpDown();
    });
    
    
    body * {
      box-sizing: border-box;
    }
    .container {
      max-width: 1200px;
      margin: 0 auto;
    }
    .slider {
      width: 100%;
      height: 300px;
      position: relative;
      overflow: hidden;
    }
    .slider .slider-nav {
      text-align: center;
      position: absolute;
      padding: 0;
      margin: 0;
      left: 10px;
      right: 10px;
      bottom: 2px;
      z-index: 30;
    }
    .slider .slider-nav li {
      display: inline-block;
      width: 20px;
      height: 3px;
      margin: 0 1px;
      text-indent: -9999px;
      overflow: hidden;
      background-color: rgba(255, 255, 255, .5);
    }
    .slider .slider-nav a {
      display: block;
      height: 3px;
      line-height: 3px;
    }
    .slider .slider-nav li.activeSlide {
      background: #fff;
    }
    .slider .slider-nav li.activeSlide a {
      display: none;
    }
    .slider .slider-container {
      width: 100%;
      text-align: center;
    }
    .slider .slider-container a {
      display: block;
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
    }
    .slider .slider-container img {
      transform: translateX(-50%);
      margin-left: 50%;
    }
    
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <div class="container">
      <div class="slider slider-homepage">
        <div class="slider-container">
          <a href="#">
            <img src="https://picsum.photos/1200/300/?gravity=east" alt="">
          </a>
          <a href="#">
            <img src="https://picsum.photos/1200/300/?gravity=south" alt="">
          </a>
          <a href="#">
            <img src="https://picsum.photos/1200/300/?gravity=west" alt="">
          </a>
        </div>
      </div>
    </div>
    
    

  • 解決した方法 # 3

    キューを使用できます。箇条書きをクリックするたびにキューに追加され、キューを実行します。このようなもの:

    {
        let
                transitionQueue = [],
                transitioning = false;
        function doTransition() {
                displayImageBeforeClick = $(".slider-container .active");
                $('.slider-nav a').closest('li').removeClass('activeSlide');
                transitionQueue.shift().closest('li').addClass('activeSlide');
                // Reset autoadvance if user clicks bullet
                if (event.originalEvent !== undefined) {
                  clearInterval(autoAdvance);
                  autoAdvance = setInterval(advanceFunc, animationInterval);
                }
                setActiveSlide();
                slideUpDown();
                if (transitionQueue.length)
                    setTimeout(doTransition, animationSpeed)
                else
                    transitioning = false;
        }
        function callTransition() {
            if (!transitioning) {
                transitioning = true;
                doTransition();
            }
        }
        $('.slider-nav a').click(function () {
            transitionQueue.push($(this));
            callTransition();
        });
    }
    
    

    私はこれをテストしていないので...

  • 解決した方法 # 4

    これはあなたの質問に厳密に答えているわけではありませんが、実際の問題を解決する方法の1つは、スライダーの扱いを変えることです。

    1)スライドコンテナーを絶対にし、コンテナーを相対にする

    .slider-homepage {
        position: relative;
    }
    .slider .slider-container {
        position: absolute;
    }
    .slider .slider-nav {
        //position: absolute; Remove this
    }
    
    

    2)クリック時にスライドを配置する代わりに、スライダーコンテナーを正しい位置に移動します

    var slideUpDown = function() {
        $('.slider-container').stop().animate(
            {top: activeIdx * slideHeight * -1}, 
            {duration: animationspeed}
        );
    };
    
    

    これにより、画像が重複することはありません。

    ここにフィドルがあります。コードは確かにリファクタリングできますが、調べる時間はあまりありませんでした。スライダー。

関連記事

  • 前へ java - JPAクエリ:サブクエリをグループ化条件に結合する
  • 次へ ruby on rails - 種をまくが複製しない方法