Enable CSS slideshow autoplay with JavaScript

偶尔善良 提交于 2021-02-08 09:26:06

问题


I made a simple slideshow using only CSS, where on the radio button click, the margin of the element changes so it displays the desired slide. You can see how it works in the code snippet below. I also made this slideshow auto play with JavaScript. The script checks the next radio button in the list every 3 seconds.

Now I need help to make the slideshow auto play in a loop and to also stop auto play when you check any radio button manually.

$(document).ready(function() {

  function autoplay() {
$("input[name=radio-button]:checked").nextAll(':radio:first').prop('checked', true);
  };
  
  setInterval(autoplay, 3000);

});
body {
margin: 0;
padding: 0;
}

.slider {
  width: 300%;
  transition: margin 1s;
  height: 100px;
}

#radio-button1:checked ~ .slider {
  margin-left: 0%;
}

#radio-button2:checked ~ .slider {
  margin-left: -100%;
}

#radio-button3:checked ~ .slider {
  margin-left: -200%;
}

.slider-item {
  float: left;
  width: 33.33%;
  height: 100%;
}
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<input type="radio" name="radio-button" id="radio-button1" checked />
<input type="radio" name="radio-button" id="radio-button2" />
<input type="radio" name="radio-button" id="radio-button3" />

<div class="slider">
  <div class="slider-item" style="background: #F00"></div>
  <div class="slider-item" style="background: #0F0"></div>
  <div class="slider-item" style="background: #00F"></div>
</div>

回答1:


Create a curr variable, increment it inside the interval and use Modulo % to loop it back to 0:

jQuery(function($) { // DOM ready and $ alias in scope

  var curr = 0;

  function autoplay() {
    curr = ++curr % 3; // Increment and Reset to 0 when 3
    $("[name=radio-button]")[curr].checked = true;
  }

  setInterval(autoplay, 3000);

});
body {
  margin: 0;
  padding: 0;
}

.slider {
  width: 300%;
  transition: margin 1s;
  height: 100px;
}

#radio-button1:checked~.slider {
  margin-left: 0%;
}

#radio-button2:checked~.slider {
  margin-left: -100%;
}

#radio-button3:checked~.slider {
  margin-left: -200%;
}

.slider-item {
  float: left;
  width: 33.33%;
  height: 100%;
}
<input type="radio" name="radio-button" id="radio-button1" checked />
<input type="radio" name="radio-button" id="radio-button2" />
<input type="radio" name="radio-button" id="radio-button3" />

<div class="slider">
  <div class="slider-item" style="background: #F00"></div>
  <div class="slider-item" style="background: #0F0"></div>
  <div class="slider-item" style="background: #00F"></div>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

The better way:

  • Overflow a super parent so you don't get scrollbars
  • Use display: flex; instead of ugly floats.
  • Use $('.slider').each( so you can have multiple sliders in a single page!
  • Create a anim() play() and stop() function to control what happens.
  • Animate using transform: and transition, since transition is GPU accelerated. Whilst margins are not, and require reflow and repaint.
  • Animate the transform by using curr * -100 %
  • Use curr %= tot (Modulo operator) to loopback the curr index to 0 when needed.
  • Why create buttons manually? Create your slides manually and let JS create the buttons for you.
  • Use setInterval by storing it into a variable itv
  • To stop your auto-animation use clearInterval(itv)
  • Use .hover(stop, play) to stop on mouseenter and autoplay on mouseleave

$('.slider').each(function(slider_idx) { // Use each, so you can have multiple sliders

  let curr = 0;             // Set current index
  let itv = null;           // The interval holder
  
  const $slider = $(this);
  const $nav    = $('.slider-nav', $slider);
  const $items  = $('.slider-items', $slider);
  const $item   = $('.slider-item', $slider);
  const tot = $item.length; // How many
  const btns = [...new Array(tot)].map((_, i) => $('<input>', {
    type: 'radio',
    name: `slider-btn-${slider_idx}`,
    checked: curr == i,
    change() { // On button change event
      curr = i; // Set current index to this button index
      anim();
    }
  })[0]);
    
  function anim() {
    $items.css({transform: `translateX(-${curr*100}%)`}); // Animate
    btns[curr].checked = true; // Change nav btn state
  }

  function play() {
    itv = setInterval(() => {
      curr = ++curr % tot; // increment curr and reset to 0 if exceeds tot
      anim(); // and animate!
    }, 3000); // Do every 3sec
  }
  
  function stop() {
    clearInterval(itv);
  }

  $nav.empty().append(btns);   // Insert buttons
  $slider.hover(stop, play);   // Handle hover state
  play();                      // Start autoplay!

});
/*QuickReset*/ * {margin: 0; box-sizing: border-box;}

.slider {
  position: relative;
  height: 100px;
}

.slider-overflow {
  overflow: hidden; /* use an overflow parent! You don't want scrollbars */
  height: inherit;
}

.slider-items {
  display: flex; /* Use flex */
  flex-flow: row nowrap;
  height: inherit;
  transition: transform 1s; /* Don't use margin, use transform */
}

.slider-item {
  flex: 0 0 100%;
  height: inherit;
}

.slider-nav {
  position: absolute;
  width: 100%;
  bottom: 0;
  text-align: center;
}
<div class="slider">

  <div class="slider-overflow">
    <div class="slider-items"> <!-- This one will transition -->
      <div class="slider-item" style="background:#0bf;">curr = 0</div>
      <div class="slider-item" style="background:#fb0;">curr = 1</div>
      <div class="slider-item" style="background:#f0b;">curr = 2</div>
    </div>
  </div>
  
  <div class="slider-nav">
    <!-- JS will populate buttons here -->
  </div>
  
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

So both DIV elements .slider-nav and .slider-overflow need to be inside of the common parent .slider - so that we properly stop (pause) the auto-animation after any interaction with those elements.




回答2:


Looping the Slideshow

To loop the slideshow, you'll want to modify your autoplay function to:

  • Get the list of all radio buttons,
  • Determine which one is checked,
  • Uncheck that and check the next one in the list,
    • Paying special attention to wrap back to the first one if already at the end.

I'll rename the function next.

function next() {
  // get all the radio buttons.
  var buttons = $('input[name="radio-button"]');

  // look at each one in the list.
  for (let i = 0; i < buttons.length; i++) {

    // if this one isn't the checked one, move on to the next.
    if (!buttons[i].checked) {
      continue;
    }

    // okay, so this one is checked. let's uncheck it.
    buttons[i].checked = false;

    // was this one at the end of the list?
    if (i == buttons.length - 1) {
      // if so, the new checked one should be the first one.
      buttons[0].checked = true;
    } else {
      // otherwise, just the new checked one is the next in the list.
      buttons[i + 1].checked = true;
    }

    // now that we've made that change, we can break out of the loop.
    break;
  }
}

As a bonus, you can easily make a similar function called prev to go in the opposite direction.

Stopping the Slideshow

When you manually click a radio button, the slideshow should stop. To stop the slideshow, you need to clear the interval that you already set.

The .setInterval() function returns an "interval id". This id can be used to make changes to the interval later on -- like stopping it.

var timer = setInterval(next, 3000);

Then, later on, you'll want to pass that timer value back into clearInterval to stop the timer.

clearInterval(timer);

It would be easier to factor that into two functions, start and stop and let the timer value be global:

var timer;

function start() {
  timer = setInterval(next, 3000);
}

function stop() {
  clearInterval(timer);
}

So now you can call the stop function whenever any of the radio buttons receive a click event:

$('input[name="radio-button"]').on('click', stop);

Full Example

This is your code with the modifications described above.

I've added buttons for "start", "stop", "prev", and "next" -- these aren't necessary for things to function. They're just there for demonstration purposes.

$(document).ready(function() {
  /* the list of buttons is not dynamic, so rather than fetching the list of
   * buttons every time `next` or `prev` gets executed, we can just fetch it
   * once and store it globally. */
  var buttons = $('input[name="radio-button"]');
  var timer;
  
  function start() {
    timer = setInterval(next, 3000);
  }
  
  function stop() {
    clearInterval(timer);
  }

  function next() {
    for (let i = 0; i < buttons.length; i++) {
      if (!buttons[i].checked) {
        continue;
      }
      buttons[i].checked = false;
      if (i == buttons.length - 1) {
        buttons[0].checked = true;
      } else {
        buttons[i + 1].checked = true;
      }
      break;
    }
  }
  
  function prev() {
    for (let i = 0; i < buttons.length; i++) {
      if (!buttons[i].checked) {
        continue;
      }
      buttons[i].checked = false;
      if (i == 0) {
        buttons[buttons.length - 1].checked = true;
      } else {
        buttons[i - 1].checked = true;
      }
      break;
    }
  }
  
  start();
  
  buttons.on('click', stop);
  
  /* these next lines are unnecessary if you aren't including the buttons */
  $('#start').on('click', start);
  $('#stop').on('click', stop);
  $('#next').on('click', next);
  $('#prev').on('click', prev);
});
body {
  margin: 0;
  padding: 0;
}

.slider {
  width: 300%;
  transition: margin 1s;
  height: 100px;
}

#radio-button1:checked~.slider {
  margin-left: 0%;
}

#radio-button2:checked~.slider {
  margin-left: -100%;
}

#radio-button3:checked~.slider {
  margin-left: -200%;
}

.slider-item {
  float: left;
  width: 33.33%;
  height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<input type="radio" name="radio-button" id="radio-button1" checked />
<input type="radio" name="radio-button" id="radio-button2" />
<input type="radio" name="radio-button" id="radio-button3" />

<div class="slider">
  <div class="slider-item" style="background: #F00"></div>
  <div class="slider-item" style="background: #0F0"></div>
  <div class="slider-item" style="background: #00F"></div>
</div>

<!-- these buttons are unnecessary, they are only for demonstration purposes -->
<button id="start">Start</button>
<button id="stop">Stop</button>
<button id="prev">Prev</button>
<button id="next">Next</button>


来源:https://stackoverflow.com/questions/60660673/enable-css-slideshow-autoplay-with-javascript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!