【问题标题】:Enable CSS slideshow autoplay with JavaScript使用 JavaScript 启用 CSS 幻灯片自动播放
【发布时间】:2020-03-12 19:24:13
【问题描述】:

我只使用 CSS 制作了一个简单的幻灯片,单击单选按钮时,元素的边距会发生变化,因此它会显示所需的幻灯片。您可以在下面的代码 sn-p 中看到它是如何工作的。我还用 JavaScript 制作了这个幻灯片自动播放。该脚本每 3 秒检查一次列表中的下一个单选按钮。

现在我需要帮助来让幻灯片自动播放循环播放,并且还需要在您手动选中任何单选按钮时停止自动播放

$(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>

【问题讨论】:

  • 这能回答你的问题吗? javascript slider not slide automatically
  • 您不需要循环,因为它会阻止浏览器呈现,只需设置一个检查下一个radioButton 的函数并在setInterval 内部调用它
  • @disinfor 不,因为我没有此滑块的下一个和上一个按钮。
  • 将另一个帖子标记为重复并不意味着它与您的问题完全相同,而是与您所问的内容非常相似。通常它需要您阅读副本并相应地调整您的代码。
  • @disinfor 我已经阅读了这篇文章,甚至在你建议之前。如果它可以帮助我,我不会发布这个。

标签: javascript jquery html css function


【解决方案1】:

创建一个curr 变量,在区间内递增,并使用模% 将其循环回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>

更好的方法:

  • 溢出一个超级父,所以你不会得到滚动条
  • 使用display: flex; 代替ugly 浮动。
  • 使用$('.slider').each(,这样您就可以在一个页面中拥有多个滑块!
  • 创建一个anim() play()stop() 函数来控制发生的事情。
  • 使用transform:transition 制作动画,因为过渡是GPU 加速的。虽然边距不是,但需要回流和重绘。
  • 使用curr * -100 % 为变换设置动画
  • 在需要时使用curr %= tot(模运算符)将curr 索引环回为0。
  • 为什么要手动创建按钮?手动创建幻灯片,让 JS 为您创建按钮。
  • 通过将setInterval 存储到变量itv 中来使用它
  • 要停止自动动画,请使用 clearInterval(itv)
  • 使用.hover(stop, play) 在 mouseenter 时停止并在 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>

因此,DIV 元素 .slider-nav.slider-overflow 都需要在公共父元素 .slider 内 - 这样我们才能在与这些元素进行任何交互后正确停止(暂停)自动动画。

【讨论】:

  • +1 我试图避免在我的答案中过多地修改原始代码,但我推荐本示例中使用的技术而不是我的答案中使用的技术。
  • @Roko C. Buljan 这太棒了,我无话可说,我花了很多天试图制作一个简单的滑块,但由于我不懂 JS,所以没能做到!我完全忘记了悬停,你甚至实现了它,它非常有用。一切都像魅力一样!只有一件事——我希望能够自定义单选按钮,因为它对我正在制作的设计非常重要。以前,我使用单选按钮的标签来做到这一点,但在我的代码 sn-p 中删除了它们以使其更短。那么,有没有办法快速修改 JS 代码,以便我可以将标签样式化为按钮?
  • 顺便说一句,我使用了您提供的第二种解决方案,当然这是更好的方法!我不知道该怎么感谢你....
  • 你可以实现这个,例如:stackoverflow.com/a/17541916/383904
  • @RokoC.Buljan 经过 3 个小时的尝试,我终于设法使用 JS 为每个单选按钮添加了一个标签。这是代码:function addLabels() { var radioButton = document.getElementsByTagName("input"); for (var i = 0; i &lt; radioButton.length; i++) { var label = "&lt;label for='" + radioButton[i].id + "'&gt;&lt;/label&gt;"; $(label).insertAfter(radioButton[i]); } } addLabels(); 然后我将这些标签样式化为 CSS 中的按钮并隐藏单选按钮。为了使这段代码正常工作,我必须在 const "btns" 内的 JS 代码中添加一行:id: 'radio-button'+[i],
【解决方案2】:

循环播放幻灯片

要循环播放幻灯片,您需要将 autoplay 函数修改为:

  • 获取所有单选按钮的列表,
  • 确定检查哪一个,
  • 取消选中并选中列表中的下一个,
    • 如果已经在末尾,请特别注意回绕到第一个。

我将把函数重命名为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;
  }
}

作为奖励,您可以轻松地创建一个名为 prev 的类似函数,以实现相反的方向。

停止幻灯片放映

当您手动单击单选按钮时,幻灯片应该会停止。要停止幻灯片放映,您需要清除已设置的间隔。

.setInterval() 函数返回一个“间隔 id”。此 id 可用于稍后更改间隔——比如停止它。

var timer = setInterval(next, 3000);

然后,稍后,您需要将该 timer 值传递回 clearInterval 以停止计时器。

clearInterval(timer);

将其分解为两个函数会更容易,startstop 并让 timer 值是全局的:

var timer;

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

function stop() {
  clearInterval(timer);
}

所以现在您可以在任何单选按钮收到click 事件时调用stop 函数:

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

完整示例

这是您的代码,经过上述修改。

我添加了用于“开始”、“停止”、“上一个”和“下一个”的按钮——这些按钮并不是运行所必需的。它们只是为了演示目的。

$(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>

【讨论】:

  • 为什么不缓存var buttons
  • 此外,时间间隔与用户输入混淆,导致用户体验不佳
  • @RokoC.Buljan 我同意你的观点,我只是专注于回答所提出的问题。
  • 而不是中断和继续以及大量的 o if 语句,只需创建一个 c 变量计数器并简单地在 prev / next 上增加和减少 c 并设置根据eq index 相应检查状态。
  • 这是对您的确切代码的完全简化的重制 jsbin.com/veluqigequ/edit?html,css,js,console,output(但仍然错过了 UX 改进)
猜你喜欢
  • 2012-04-07
  • 2013-11-24
  • 1970-01-01
  • 2021-10-04
  • 1970-01-01
  • 2015-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多