【问题标题】:How to make autosliding carousel thumbnail change background image when active如何在活动时使自动滑动轮播缩略图更改背景图像
【发布时间】:2020-09-27 16:48:02
【问题描述】:

我的问题有 3 个部分。对此 JS 问题的任何部分的任何帮助将不胜感激。我正在尝试通过反复试验来学习和理解 JS。

我创建了这个漂亮的旅行登录页面https://portfolioprime.github.io/Nature%20carousel/glidejs.html,带有一个使用 Glide.js 的缩略图轮播,非常酷且运行良好。旋转木马向左移动,并带有箭头按钮来手动控制幻灯片。

但我一直在尝试实现一个香草 JS 轮播滑块,但我失败了。挣扎了 2 天,我能做到的最好的事情就是让一个旋转木马项目左右移动。见https://portfolioprime.github.io/Nature%20carousel/

我想要的是让旋转木马自动向左滑动,用箭头按钮手动控制滑块。

我使用querySelectorAll('.carousel-items') 定位所有轮播项目并将left:-274px 添加到轮播容器glide__slides

这是我的 JS 代码。

// var & event-listener buttons
document.querySelector(".left").addEventListener("click", slideLeft);

document.querySelector(".right").addEventListener("click", slideRight);

// Function slide left
function slideLeft(left) {
  document.querySelector('.glide__slides').style.left = left;
}
// Function slide left
function slideRight(right) {
  document.querySelector('.glide__slides').style.left = right;
}

其次,我想要一个活动的轮播项目,当它处于活动状态时会自动更改背景图片。

现在我有hero.style.background = var;,我已经在每个轮播项目上用onclick = function('01.jpg') 更改了onclick。

这是代码。

// Change Hero Img
 function heroChange(hmmm) {
  var hero = document.querySelector('.hero');
  hero.style.background = hmmm;
 }

所以我想我会将 EventListeners 添加到 carousel-items 并像这样向 carousel-item 添加一个活动类,

var slides = document.querySelectorAll('.carousel-items');

function changeBgImg() {
  slides.forEach(s => s.classList.remove('active');
  this.classList.add('active');

//change the bg image === this
//But I have no idea how to do that

}

第三,我使用上面相同的函数获得了内容、背景和轮播指示器,但它看起来像是很脏的代码。 HTML 有每个.carousel-item,有十个,每个调用 4 个函数。它看起来像这样:

      <div class="glide hero-carousel">
        <div class="glide__track" data-glide-el="track">
          <ul class="glide__slides">

            <li class="glide__slide carousel-item" 
              onclick="heroChange('url(images/02.jpg) bottom/cover no-repeat'); 
              number('01'); 
              h4('Destination Shire'); 
              h1('Valley<br> of Dreams');">

              <div class="carousel-text">
                <p>Destination Shire</p>
                <h3>Valley<br> of Dreams</h3>
              </div>

            </li>

            <li class="glide__slide carousel-item" 
              onclick="heroChange('url(images/03.jpg) bottom/cover no-repeat'); 
              number('02'); 
              h4('Destination Westwood'); 
              h1('Misty<br> Woodlands');">

              <div class="carousel-text">
                <p>Destination Westwood</p>
                <h3>Misty<br> Woodlands</h3>
              </div>

            </li>

         </ul>
       </div>
     </div>

所以看起来很恶心。虽然它可以工作,但我希望找到一种更优雅的方式来实现这一点,将所有这些函数放入一个函数中,按顺序执行每个部分。

最后,我想让点击动画过渡,但这完全是另一锅鱼。

就是这样。呼!

感谢您抽出宝贵的时间,我很感激。你能提供的任何帮助都会让我成为一个更好的设计师。实际上,我有很多项目将从答案中受益。

如果您至少可以提供第 2 部分和第 3 部分的帮助:将代码清理为 1 个函数并在活动类上更改 bg-image,那将是一个很大的帮助。

JS 可以做的事情太多了,我在 Google 和 YouTube 上找不到答案。

再次感谢您。

更新:

我已经使用 margin-left 编辑了滑块,如这个问题所示:

vanilla javascript carousel not sliding

// var & event-listener buttons
document.querySelector(".left").addEventListener("click", slideLeft);
document.querySelector(".right").addEventListener("click", slideRight);


let marginLeft = 0;
const slides = document.querySelector('.glide__slides');

// Function slide left
function slideLeft() {
  marginLeft += 264;
  slides.style.marginLeft = marginLeft + 'px';
  console.log(getComputedStyle(slides).marginLeft);
}
// Function slide Right
function slideRight() {
  marginLeft -= 264;
  slides.style.marginLeft = marginLeft + 'px';
  console.log(getComputedStyle(slides).marginLeft);
}

现在轮播已手动移动 1 张幻灯片。 仍然不完全理解为什么我上面的代码不起作用。如果有人可以向我解释,那就太好了。

我还有一些问题:

  1. 在幻灯片末尾自动滑动和循环播放。

  2. 让活动滑块自动更改背景。此时它只改变onclick。

  3. 找到一种方法来整理函数调用和函数。

【问题讨论】:

  • 我对这个问题的回答 [link]stackoverflow.com/questions/63861444/… 可能很有趣 - 它是纯 javascript/css 并允许无限滚动。明天我会回来更详细地查看您的问题。
  • 我已经给出了部分答案,这是一种在运行时创建令人讨厌的代码并使维护滑块更简单的方法 - 添加、删除或更改幻灯片的顺序。今天晚些时候,我将研究使用原生 JavaScript 创建无限滑块。同时,您能说一下您希望在单击幻灯片时发生什么,如果滑块已经自动移动,当单击箭头时会发生什么?
  • 谢谢@A Haworth,我会查看您上面的链接。
  • 谢谢,@A Haworth,我会查看您上面的链接。我会说当单击幻灯片时 .hero 背景图像应该改变。单击按钮时,幻灯片应朝该方向移动一张幻灯片。最佳的做法是让滑块在幻灯片或 btn 悬停时暂停滚动。看看 portfolioprime.github.io/Nature%20carousel/…>。我让它在这里自动滑动,但在最后一张幻灯片后它没有重置滑块。而且也不会暂停。
  • 总结:滑块从右​​到左自动开始,当一个人到达左边时会有一个暂停,此时背景图像应该改变(?)。如果用户悬停在幻灯片或 btn 上(这是箭头之一吗?),滑块会暂停。单击箭头会沿箭头方向移动一张幻灯片(并停止任何自动滑动??)。整个事情应该是一个连续的循环。这一切都可以用 CSS 动画来完成——相当简单。我将在大约 2 小时内更新我的答案。

标签: javascript typescript


【解决方案1】:

该问题询问了有关如何简化代码以及如何使用原生 JavaScript 来创建连续滚动的滑块的各种想法。

代码最初使用 glider 并且可能更简单的东西足以获得所需的结果,例如使用 animationend 事件在幻灯片到达左侧时更改背景。但是,慢慢吃大象我会先解决令人讨厌的代码(第 3 部分)。

虽然 HTML 看起来相当令人生畏,例如,每个 li 元素都需要点击 4 次,但这是目前所需要的,所以让我们研究一下在运行时创建它。这给了我们更容易维护的代码。例如,如果我们想删除一张幻灯片,或者改变幻灯片的顺序或者添加一张幻灯片,我们可以只改变下面定义的滑块数组,剩下的事情由 JavaScript 完成。

问题的第 1 部分询问了滑动。我们使用 CSS 动画来滑动整个 ul 元素,定义如下,其中 33vw 是幻灯片的总宽度(包括边距/填充)

@keyframes sliding0 {
  0% { left: 0; }
  30% { left: 0; }
  100% { left: -33vw; }
}

我们为元素添加了一个事件监听器来捕获动画结束事件,因为当 ul 滑动了一张幻灯片的宽度时,我们想要更改英雄图像,并且我们想要将刚刚消失的幻灯片放在 infinie 的背面滑动将起作用。然后我们再次设置动画运行。

有关如何处理此事件和其他事件的详细信息,请参阅 sn-p。它还显示了 changeHero 函数如何工作,这是问题的第 2 部分。请注意,sn-p 或多或少在 SO 环境中工作,尽管偶尔会部分忽略悬停动作。在你自己的机器上运行代码应该没问题。

<!DOCTYPE html>
<html>
<head>
<style>

@keyframes sliding0 {
  0% { left: 0; }
  30% { left: 0; }
  100% { left: -33vw; }
}

@keyframes sliding1 {
  0% { left: 0; }
  30% { left: 0; }
  100% { left: -33vw; }
}

body {
  background-repeat: no-repeat no-repeat;
  background-size: cover;
  background-position: center center;
}
div .glide_track {
  position: relative;
  width: 100vw;
  overflow-x: hidden;
}

ul {
  position:relative;
  left: 0;
  width: 330vw;
  height:100vh;
  animation-name: sliding0;
  animation-duration: 3s;
  animation-delay: 0s;
  animation-iteration-count: 1;
  animation-timing-function: linear;
  margin: 0;
  padding: 0;
  list-style-type: none;
}

li {
  position: relative;
  left:0;
  top:0;
  float:left;
  width: 32vw;
  height:30vw;
  display: inline-block;
  margin: 0;
  margin-right: 1vw;
  padding: 0;
  background-size: cover;
  background-repeat: no-repeat no-repeat;
  background-position: center center;
}

</style>
</head>
<body>
<script>

// we put the two lots of text and the image url for each slide in an array in the order they are to be shown
// this makes it easier to maintain when you want to add or remove a slide or change their order
// we only have one slider at the moment but this makes it more general

// these are the offsets in the array describing a slide. Done as indexes rather than named as easier to set up sliders array
const img = 0;
const text1 = 1;
const text2 = 2;

const sliders = [
  [
    ['https://ahweb.org.uk/boxfordmosaic.jpg','Shire','Valley<br> of Dreams'],
    ['https://ahweb.org.uk/gear-in-turbine-house-reading.jpg','Westwood','Misty Woodlands'],
    ['https://ahweb.org.uk/tricycle-in-abbey-ruins.jpg','Shire','Valley<br> of Dreams'],
    ['https://ahweb.org.uk/boxfordmosaic.jpg','Shire','Valley<br> of Dreams'],
    ['https://ahweb.org.uk/gear-in-turbine-house-reading.jpg','Westwood','Misty Woodlands'],
    ['https://ahweb.org.uk/tricycle-in-abbey-ruins.jpg','Shire','Valley<br> of Dreams'],
    ['https://ahweb.org.uk/boxfordmosaic.jpg','Shire','Valley<br> of Dreams'],
    ['https://ahweb.org.uk/gear-in-turbine-house-reading.jpg','Westwood','Misty Woodlands'],
    ['https://ahweb.org.uk/tricycle-in-abbey-ruins.jpg','Shire','Valley<br> of Dreams'],
    ['https://ahweb.org.uk/tricycle-in-abbey-ruins.jpg','Shire','Valley<br> of Dreams']
  ]
];

// go through each slider and create its outer divs and its ul element
sliders.forEach(createSlider);

function createSlider(slider,sliderno) {
  const div1 = document.createElement('DIV');
  const div2 = document.createElement('DIV');
  const ul = document.createElement('UL');

  div1.classList.add("glide","hero-carousel");
  div2.classList.add("glide_track");
  div2.setAttribute("data-glide-el","track");

  div1.appendChild(div2);
  div2.appendChild(ul);
  document.body.appendChild(div1);

  ul.classList.add("glide__slides");
    
  ul.addEventListener("animationend", animationEnd);
 
  slider.forEach(createLi);

  function createLi(slide,slideNo) {
    const li = document.createElement('LI');
    li.classList.add("glide__slide","carousel-item");
    li.style.backgroundImage='url('+slide[img]+')';
    li.addEventListener("click",slideClicked);
    li.addEventListener("mouseover",slideHovered);
    li.addEventListener("mouseout",slideUnhovered);
    
    li.setAttribute('data-slideno','0' + slideNo);//! needs generalising if you have >10 slides !

    ul.appendChild(li);

    const div = document.createElement('DIV');
    const p = document.createElement('P');
    const h3 = document.createElement('H3');

    p.innerHTML = slide[text1];
    div.appendChild(p);
    h3.innerHTML = slide[text2];
    div.appendChild(h3);

    li.appendChild(div);
  }
}

// this is for testing, in real version use whatever required (i.e. whichever element is to have the hero image)
function ahHeroChange(backgroundImage) {  
  document.body.style.background = backgroundImage + " bottom/cover no-repeat";
}

function slideClicked(event) {
  var slide = event.target;
  var slideNo = slide.getAttribute('data-slideno');
  
  // make the hero image the same as the slide's
  ahHeroChange(slide.style.backgroundImage);
  
/* I don't know what these functions do - they were executed in the original on a click 

  number(slideno);
  h4(slide.firstElementChild.querySelector('p').innerHTML);// text1 of the slide is passed to h4
  h1(slide.firstElementChild.querySelector('h3').innerHTML;// text2 of the slide is passed to h1

*/
}

function slideHovered(event) {
  var slide = event.target;
  var slider = slide.parentElement;
  slider.style.animationPlayState = 'paused';
  ahHeroChange(slide.style.backgroundImage);
}

function slideUnhovered(event) {
  var slide = event.target;
  var slider = slide.parentElement;
  
  //restore the hero image to the first one in the slider
  ahHeroChange(slider.firstElementChild.style.backgroundImage);
  
  //get the animation running again
  slider.style.animationPlayState = 'running'; 
}

function animationEnd(event) {
   //find the element that was clicked (it will be a ul element representing a slider)
   var slider = event.target;
   
  //take the first slide off the list and put it back at the end
  slider.append(this.firstElementChild);
  
  //change the hero image to the slide which is now the leftmost - use modified heroChange in the final version
  document.body.style.backgroundImage = this.firstElementChild.style.backgroundImage;
  
  // toggle the animationName (to an identical keyframes action) to force the animation to start again
  slider.style.animationName='sliding'+(Number(event.animationName.replace('sliding',''))+1)%2;
}

</script>
</body>
</html>

【讨论】:

  • 感谢您简洁的总结和您在解释中的详细说明。非常感谢。我目前正在设置这个。将发布我的进度更新。
  • 我已经让你的代码在上面工作了。见 portfolioprime.github.io/Nature%20carousel/index-new-try.html> ,虽然我不是很了解,但从中学到了很多,即。 createElementappendChild。我删除了一些 glider.js 样式和 div 以稍微简化它。
  • 我有一些问题。为什么要在 function createLis 中创建和嵌套 function creatLi() 而不是继续在顶部函数中创建它们?你能解释一下"slideClicked(this,"+slideno+")这个代码和function slideClicked(slide,slideno)吗?抱歉,这似乎是一个非常愚蠢的问题,只是不要明白这部分。
  • 我可能误命名了 createLis,因为它正在为滑块创建整个事物(div 和 ul)。 sliders.forEach(createLis);一次通过一个滑块(我知道您现在只需要一个,但对于一般情况),并且为每个滑块创建 div 和 ul。如果我们称它为 createSlider 会更清楚吗?对于每个滑块,您必须遍历每个幻灯片,创建其 li 元素,这就是 slider.forEach(createLi) 所做的。我本可以使用匿名函数,但我发现它们更难阅读。
  • function slideClicked(slide,slideno) 是替换您的 4 个函数的函数 - 实际上它只是将它们全部放入一个函数中。我没有以任何方式解释它们,它直接来自每个 li 元素中的内容,只是将它们放在一起更整洁。 "slideClicked(this,"+slideno+")" 创建一个字符串 slideClicked(this,2)(在幻灯片编号 2 的情况下)。这是将在单击时进行的 javascript 调用(即,您的 4 个函数调用全部归入一个函数 slideClicked)。 JS 中的 + 号用于添加数字和连接字符串。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-22
  • 1970-01-01
  • 1970-01-01
  • 2014-11-13
  • 1970-01-01
  • 1970-01-01
  • 2020-12-27
相关资源
最近更新 更多