香草javascript&CSS图像滑块无法正常工作 [英] vanilla javascript & css image slider not working properly

查看:63
本文介绍了香草javascript&CSS图像滑块无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用一些javascript和CSS创建了一个包含许多图像的图像滑块.我只是使用客户端宽度来获取图像的大小(略有变化),并使用计数器变量计算了transformX的距离.最后添加了一个CSS过渡.但是我似乎无法使滑块正确地转换整个图像.我不知道为什么会出错.我在计算中使用了"vw"来表示响应速度.我是javascript的新手,并且很乐意为代码的其他部分提供关于其他部分的任何提示.

这是JS小提琴链接- https://jsfiddle.net/n6smpv2j/15/

HTML

 < div id =" lookbook"data-tab-content class =黑文本".< div class ="lookbook-nav">< button id ="left">←</button>< button id ="right">→</button></div>< div class ="lookbook">< div class =滑块">< img src =" https://loremflickr.com/640/360"id ="lastClone"alt ="< img src =" https://picsum.photos/640/400>< img src =" https://loremflickr.com/640/360">< img src ="https://picsum.photos/640/400">< img src =" https://loremflickr.com/640/360">< img src ="https://picsum.photos/640/400">< img src =" https://loremflickr.com/640/360">< img src =" https://picsum.photos/600/400">< img src =" https://fillmurray.com/600/330>< img src =" https://picsum.photos/600/400">< img src =" https://fillmurray.com/600/330>< img src =" https://picsum.photos/600/400">< img src =" https://loremflickr.com/640/360">< img src =" https://picsum.photos/600/400">< img src =" https://loremflickr.com/640/360">< img src =" https://picsum.photos/600/400"id ="firstClone"alt ="</div></div></div> 

JS

  const滑块= document.querySelector('.slider');const slidesImages = document.querySelectorAll('.slider img');const leftbtn = document.querySelector('#left');const rightbtn = document.querySelector('#right');让计数器= 1;const size = slideImages [0] .clientWidth;slide.style.transform ='translateX('+(-size * counter)+'vw)';rightbtn.addEventListener('click',()=> {如果(counter> = sliderImages.length-1)返回;slide.style.transition =变换0.4s缓入";计数器++;slide.style.transform ='translateX('+(-size * counter)+'vw)'})leftbtn.addEventListener('click',()=> {如果(计数器< = 0)返回;slide.style.transition =变换0.4s缓入";柜台 - ;slide.style.transform ='translateX('+(-size * counter)+'vw)'})slide.addEventListener('transitionend',()=> {如果(sliderImages [counter] .id ==="lastClone"){slide.style.transition =无";计数器= sliderImages.length-2;slide.style.transform ='translateX('+(-size * counter)+'vw)'}如果(sliderImages [counter] .id ==="firstClone"){slide.style.transition =无";计数器= sliderImages.length-计数器;slide.style.transform ='translateX('+(-size * counter)+'vw)'}}) 

CSS

  #lookbook {宽度:100vw;高度:100vh;}.lookbook-nav {宽度:70vw;高度:10vh;左边距:15vw;边距最高:45vh;位置:绝对;显示:flex;证明内容:间隔;align-items:居中;}按钮 {边界:无;大纲:无;背景:透明;字体大小:2rem;/* font-weight:粗体;*/光标:指针;}.lookbook-nav按钮{边界:无;大纲:无;背景:透明;字体大小:2rem;/* font-weight:粗体;*/光标:指针;}按钮:悬停{不透明度:0.4;}.看看书 {宽度:56vw;高度:91vh;保证金:自动;溢出:隐藏;}.lookbook img {宽度:100%;高度:自动!重要}.slider {保证金最高:10vh;显示:flex;宽度:自动;} 

解决方案

@DecjazMach的答案解决了最重要的问题,但并未涵盖所有内容.例如,该解决方案还仍然使用第一张图像的宽度来设置可见滑块的宽度.在许多情况下都可以,但是如果第一个图像是一个瘦高个子画像,而其余的风景又反之亦然呢?

@Laiqa Mohid也欢迎任何其他建议,因此这里有一些是为了简化事情而提出的,例如,最小化JS中所需的计算以及系统只需单击即可完成的工作".您可以在这里尝试 http://bayeuxtapestry.rgspaces.org.uk/slider

注意:

滑块可见部分的大小不取决于第一张图像的大小

imgs已替换为divs +背景图片,以便无需使用javascript即可容纳不同的尺寸/纵横比-这将自动提高响应速度

这些div的尺寸都相同,因此滑块需要移动的量不取决于图像的大小

未填满整个宽度(因为它们相对太高)的图像将居中

图像也垂直居中.如果需要(例如,与滑块顶部对齐),可以通过更改.slider div

中的背景位置来更改此设置

使用transform:translateX可以,但是需要Javascript中的计算.我们可以改用CSS动画,只需要移动当前可见的幻灯片和接下来要显示的幻灯片即可.

图片服务有时不提供图片,因此我使用了自己的图片-故意设置了不同的大小和宽高比(包括人像)

使用此方法,可以有一个连续的滑块-如果用户单击的最后一个幻灯片,则显示第一个幻灯片.

这是代码:

 <!DOCTYPE html>< html>< head>< title> Slider</title><元字符集="utf-8">< style>#看看书 {宽度:100vw;高度:100vh;保证金:0;填充:0;溢出:隐藏}.lookbook-nav {宽度:70vw;高度:10vh;左边距:15vw;边距最高:45vh;位置:绝对;显示:flex;证明内容:间隔;align-items:居中;}按钮 {边界:无;大纲:无;背景:透明;字体大小:2rem;/* font-weight:粗体;*/光标:指针;}.lookbook-nav按钮{边界:无;大纲:无;背景:透明;字体大小:2rem;/* font-weight:粗体;*/光标:指针;}按钮:悬停{不透明度:0.4;}div .lookbook {宽度:56vw;}.看看书 {高度:91vh;保证金:自动;溢出:隐藏;}div.slider {保证金:0;保证金最高:10vh;height:81vh;/*这是(lookbook-margin-top)的高度-最好通过flex */位置:相对;顶:0;填充:0;宽度:100%;}@keyframes slideouttoleft {从 {左:0;能见度:可见;}至 {左:-100%;可见性:隐藏;}}@keyframes slideinfromright {从 {左:100%;能见度:可见;}至 {左:0;能见度:可见;}}@keyframes slideouttoright {从 {左:0;能见度:可见;}至 {左:100%;可见性:隐藏;}}@keyframes slideinfromleft {从 {左:-100%;能见度:可见;}至 {左:0;能见度:可见;}}.slider div {位置:绝对;顶:0;左:0;溢出:隐藏可见性:隐藏;边距:0;填充:0;宽度:100%;高度:100%;背景大小:包含;背景位置:中心中心;背景重复:不重复不重复;动画时间:0.4秒;动画延迟:0秒;animation-iteration-count:1;动画方向:正常;动画定时功能:缓入;animation-fill-mode:前进;}</style></head><身体>< div id =" lookbook"data-tab-content class =黑文本".< div class ="lookbook-nav">< button id ="left">←</button>< button id ="right">→</button></div>< div class ="lookbook">< div class =滑块"><!-从雷丁(英国)博物馆的贝叶挂毯的维多利亚时代复制品中拍摄的图像->< div样式=" background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/boat-andhorses-768x546.png);<</div>;< div样式=" background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/two-horses-300x212.png);</div< div样式=" background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/woman-and-child-1200x901.png);></div>;< div样式=" background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/archer-2-768x1100.png);</div< div样式=" background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/boat-builder-2-878x1024.png);<</div>;< div样式=" background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/group-1-768x603.png);</div< div样式=" background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/pointing-horseman-768x853.png);</div< div样式=" background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/group-2-768x619.png);</div< div样式=" background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/carrying-casket-768x556.png);</div</div></div></div>< script>const slide = document.querySelector('.slider');const slidesImages = document.querySelectorAll('.slider div');const leftbtn = document.querySelector('#left');const rightbtn = document.querySelector('#right');const numImgs = sliderImages.length;让curImg = 0;rightbtn.addEventListener('click',()=> {SliderImages [curImg] .style.animationName ='slideouttoleft';curImg =(curImg + 1)%数量;SliderImages [curImg] .style.animationName ='slideinfromright';})leftbtn.addEventListener('click',()=> {SliderImages [curImg] .style.animationName ='slideouttoright';curImg = curImg == 0?numImgs-1:Math.abs((curImg-1)%numImgs);slideleImages [curImg] .style.animationName ='slideinfromleft';})函数initialize(){slideleImages [0] .style.animationName ='slideinfromright';}window.onload =初始化</script></body></html> 

I have created an image slider with many images using some javascript and css. I just used client width to get the size of the image (which vary slightly) and calculated the translateX distance with a counter variable. Added a css transition in the end. However I can't seem to get the slider to translate the whole image correctly. I don't know why it's going wrong. I have used 'vw' in the calculations for responsiveness. I am new to javascript and would love any tips for other parts for other parts of code as well.

here is the JS fiddle link- https://jsfiddle.net/n6smpv2j/15/

HTML

<div id="lookbook" data-tab-content class="black-text">
            <div class="lookbook-nav">
               <button id="left">←</button>
               <button id="right">→</button>
            </div>
            <div class="lookbook">
               <div class="slider">
                  <img src="https://loremflickr.com/640/360" id="lastClone" alt="">
                  <img src="https://picsum.photos/640/400">
                  <img src="https://loremflickr.com/640/360">
                  <img src="https://picsum.photos/640/400">
                  <img src="https://loremflickr.com/640/360">
                  <img src="https://picsum.photos/640/400">
                  <img src="https://loremflickr.com/640/360">
                  <img src="https://picsum.photos/600/400">
                  <img src="https://fillmurray.com/600/330">
                  <img src="https://picsum.photos/600/400">
                  <img src="https://fillmurray.com/600/330">
                  <img src="https://picsum.photos/600/400">
                  <img src="https://loremflickr.com/640/360">
                  <img src="https://picsum.photos/600/400">
                  <img src="https://loremflickr.com/640/360">
                  <img src="https://picsum.photos/600/400" id="firstClone" alt="">
               </div>
            </div>
         </div>

JS

const slider = document.querySelector('.slider');
const sliderImages = document.querySelectorAll('.slider img');
const leftbtn = document.querySelector('#left');
const rightbtn = document.querySelector('#right');
let counter = 1;
const size = sliderImages[0].clientWidth;
slider.style.transform = 'translateX(' + (-size * counter) + 'vw)';

rightbtn.addEventListener('click', () => {
   if (counter >= sliderImages.length - 1) return;
   slider.style.transition = "transform 0.4s ease-in";
   counter++;
   slider.style.transform = 'translateX(' + (-size * counter) + 'vw)'
})

leftbtn.addEventListener('click', () => {
   if (counter <= 0) return;
   slider.style.transition = "transform 0.4s ease-in";
   counter--;
   slider.style.transform = 'translateX(' + (-size * counter) + 'vw)'
})

slider.addEventListener('transitionend', () => {
   if (sliderImages[counter].id === "lastClone") {
      slider.style.transition = "none";
      counter = sliderImages.length - 2;
      slider.style.transform = 'translateX(' + (-size * counter) + 'vw)'
   }
   if (sliderImages[counter].id === "firstClone") {
      slider.style.transition = "none";
      counter = sliderImages.length - counter;
      slider.style.transform = 'translateX(' + (-size * counter) + 'vw)'
   }
})

CSS

#lookbook {
   width: 100vw;
   height: 100vh;
}

.lookbook-nav {
   width: 70vw;
   height: 10vh;
   margin-left: 15vw;
   margin-top: 45vh;
   position: absolute;
   display: flex;
   justify-content: space-between;
   align-items: center;
}

button {
   border: none;
   outline: none;
   background: transparent;
   font-size: 2rem;
   /* font-weight: bold; */
   cursor: pointer;
}

.lookbook-nav button {
   border: none;
   outline: none;
   background: transparent;
   font-size: 2rem;
   /* font-weight: bold; */
   cursor: pointer;
}

button:hover {
   opacity: 0.4;
}

.lookbook {
   width: 56vw;
   height: 91vh;
   margin: auto;
   overflow: hidden;
}

.lookbook img {
   width: 100%;
   height: auto !important;
}

.slider {
   margin-top: 10vh;
   display: flex;
   width: auto;
   
}

解决方案

The answer from @DecjazMach solves the most important problem but doesn't cover everything. For example, the solution also still uses the width of the first image to set the width of the visible slider. This will be fine in many cases, but what if the first image is a skinny tall portrait and the rest landscape or vice versa?

@Laiqa Mohid also welcomed any other suggestions so here are some which come out of trying to simplify things, for example minimising the calculation needed in the JS and the 'work' the system has to do on a click. You can try it here http://bayeuxtapestry.rgspaces.org.uk/slider

Notes:

The size of the visible portion of the slider is not dependent on the dimensions of the first image

imgs have been replaced with divs + background-image so that different sizes/aspect ratios can be accommodated without any need for javascript calculation - this automatically helps responsiveness

these divs are all of the same dimensions so the amount the slider needs to move does not depend on the size of the image

images that do not fill the whole width (because they are too tall relatively) will be centred

images are also centred vertically. This can be changed if required (e.g. to align to the top of the slider) by changing the background-position in .slider div

Using a transform:translateX works but requires a calculation in the Javascript. We can use CSS animation instead and need only move the currently visible slide and the one that is to be shown next.

The image serving services sometimes did not serve an image so I have used my own - deliberately of different sizes and aspect ratios (including portrait)

Using this method it is possible to have a continuous slider - showing the first slide if the user clicks past the last one.

Here is the code:

<!DOCTYPE html>
<html>
<head>
<title>Slider</title>
<meta charset="utf-8">
<style>
#lookbook {
  width: 100vw;
  height: 100vh;
  margin:0;
  padding:0;
  overflow:hidden;
}

.lookbook-nav {
  width: 70vw;
  height: 10vh;
  margin-left: 15vw;
  margin-top: 45vh;
  position: absolute;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

button {
  border: none;
  outline: none;
  background: transparent;
  font-size: 2rem;
  /* font-weight: bold; */
  cursor: pointer;
}

.lookbook-nav button {
  border: none;
  outline: none;
  background: transparent;
  font-size: 2rem;
  /* font-weight: bold; */
  cursor: pointer;
}

button:hover {
  opacity: 0.4;
}

div .lookbook {
  width: 56vw;
}

.lookbook {
  height: 91vh;
  margin: auto;
  overflow: hidden;
}

div.slider{
  margin:0;
  margin-top: 10vh;
  height:81vh;/* this is height of (lookbook - margin-top) - probably better done through flex */
  position:relative;
  top:0;
  padding:0;
  width:100%;
}

@keyframes slideouttoleft {
  from {
   left: 0;
   visibility:visible;
  }
  to {
   left: -100%;
   visibility:hidden;
  }
}
@keyframes slideinfromright {
  from {
   left: 100%;
   visibility:visible;
  }
  to {
   left: 0;
   visibility:visible;
  }
}
@keyframes slideouttoright {
  from {
   left: 0;
   visibility:visible;
  }
  to {
   left: 100%;
   visibility:hidden;
  }
}
@keyframes slideinfromleft {
  from {
   left: -100%;
   visibility:visible;
  }
  to {
   left: 0;
   visibility:visible;
  }
}

.slider div {
  position:absolute;
  top:0;
  left:0;
  overflow:hidden;
  visibility:hidden;
  margin: 0;
  padding: 0;
  width:100%;
  height:100%;
  background-size: contain;
  background-position: center center;
  background-repeat: no-repeat no-repeat;
  animation-duration: 0.4s;
  animation-delay: 0s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-timing-function: ease-in;
  animation-fill-mode: forwards;
}
</style>
</head>
<body>

<div id="lookbook" data-tab-content class="black-text">
        <div class="lookbook-nav">
          <button id="left">←</button>
          <button id="right">→</button>
        </div>
        <div class="lookbook">
          <div class="slider">
          <!-- images taken from Reading (UK) Museum's Victorian copy of the Bayeux Tapestry -->
            <div style="background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/boat-and-horses-768x546.png);"></div>
            <div style="background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/two-horses-300x212.png);"></div>
            <div style="background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/woman-and-child-1200x901.png);"></div>
            <div style="background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/archer-2-768x1100.png);"></div>
            <div style="background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/boat-builder-2-878x1024.png);"></div>
            <div style="background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/group-1-768x603.png);"></div>
            <div style="background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/pointing-horseman-768x853.png);"></div>
            <div style="background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/group-2-768x619.png);"></div>
            <div style="background-image:url(https://rgspaces.org.uk/bayeuxtapestry/wp-content/uploads/carrying-casket-768x556.png);"></div>
          </div>
        </div>
</div>
<script>
const slider = document.querySelector('.slider');
const sliderImages = document.querySelectorAll('.slider div');
const leftbtn = document.querySelector('#left');
const rightbtn = document.querySelector('#right');
const numImgs=sliderImages.length;
let curImg = 0;

rightbtn.addEventListener('click', () => {
  sliderImages[curImg].style.animationName='slideouttoleft';
  curImg=(curImg+1)%numImgs;
  sliderImages[curImg].style.animationName='slideinfromright';
})

leftbtn.addEventListener('click', () => {
  sliderImages[curImg].style.animationName='slideouttoright';
  curImg=curImg==0? numImgs-1 : Math.abs((curImg-1)%numImgs);
  sliderImages[curImg].style.animationName='slideinfromleft';
})

function initialize() {
  sliderImages[0].style.animationName='slideinfromright';
}

window.onload=initialize;

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

这篇关于香草javascript&amp;CSS图像滑块无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆