简体   繁体   中英

Enable CSS slideshow autoplay with JavaScript

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>

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.

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM