当我开始学习JavaScript时,我真的很想了解滑块的工作原理以及可以用滑动或鼠标翻转的滑块,但是我没有找到能很好地说明我所需要的材料。一段时间后,我设法做类似的事情。现在,我想写一篇有关此的文章,以便其他想了解它的工作原理并为滑块(不仅是)创建触摸事件的人,可以更轻松地弄清楚它。我将尝试按顺序列出并通过示例性说明来支持这些解释。
我不认为自己是JavaScript方面的专家,总是有一些需要学习的东西,因此,如果您知道如何更好/更容易/更高效地编写一些代码片段,请务必在注释中编写。
内容:
- 我们将执行什么功能?
 - 编写HTML和CSS
 - 如何运作?
 - 编写JavaScript
 - 总
 - 完整版本代码
 
您可以立即看到一个示例。
1.我们将执行哪些功能?
让我们用0编写一个简单的滑块,它将具有以下功能:
- 我们实现了触摸和拖动翻转幻灯片的功能;
 - 使用箭头键切换幻灯片;
 - 分别锁定第一张和最后一张幻灯片上的箭头键←和→。
 
.
- , - , -, , , .. . . - , .
2. HTML CSS
HTML CSS?
(1 ) 200200 . - .
:

.
. , .slider-track display: flex. , , flex-shrink: 0, .

. track , .slider-list. , overflow: hidden. , .

-. ́ .slider-arrows . .slider-list (overflow: hidden) , :
.slider-list padding-bottom ;.slider-list , .slider ( ) .
́ CSS.
HTML :
<div class="slider">
  <div class="slider-list">
    <div class="slider-track">
      <div class="slide">1</div>
      <div class="slide">2</div>
      <div class="slide">3</div>
      <div class="slide">4</div>
      <div class="slide">5</div>
    </div>
  </div>
  <div class="slider-arrows">
    <button type="button" class="prev">←</button>
    <button type="button" class="next">→</button>
  </div>
</div>
← → HTML-, , .
CSS :
.slider {
  position: relative;
  width: 200px;
  height: 200px;
  margin: 50px auto 0;
  
  user-select: none;
  
  touch-action: pan-y;
}
.slider img {
  poiner-events: none;
}
.slider-list {
  width: 200px;
  height: 200px;
  overflow: hidden;
}
.slider-list.grab {
  cursor: grab;
}
.slider-list.grabbing{
  cursor: grabbing;
}
.slider-track {
  display: flex;
}
.slide {
  width: 200px;
  height: 200px;
  
  flex-shrink: 0;
  
  font-size: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid #000;
}
.slider-arrows {
  margin-top: 15px;
  text-align: center;
}
.next,
.prev {
  background: none;
  border: none;
  margin: 0 10px;
  font-size: 30px;
  cursor: pointer;
}
.next.disabled,
.prev.disabled {
  opacity: .25;
  pointer-events: none;
}
:

overflow: hidden:

, .
3. ?
transform: translate3d(x, y, z), . transform: translateX(x) will-change: transform. style match().
slideIndex. , (200px). — transform: translate3d(x, y, z) x : * . -.
, .
. touchstart ( mousedown), — touchmove (mousemove), — touchend (mouseup).
event.clientX ( ) :
3 — swipeStart, swipeAction swipeEnd.
() X ( posX1 posInit, posX1 , posInit ).
, posX1, posX2, style.transform, . posX1 .
:
posX1 posInit — , ( event.clientX). swipeStart, , 320px, posInit posX1 160. swipeAction posX1 .

posX2 — posX1 event.clientX. swipeAction, , - , " " = 161, 160 — 161 = -1, -1px. :

, , X, posX2 , . 0.5 10, ( , ́ , , ).
, (posFinal) "" (posThreshold), .
. . , :
posFinal = posInit – posX1 ( , swipeAction, , 200px, , posFinal 100).

else - , .
posThreshold , , prev() next() . posInit posX1. 320px, ́ , 0px-320px ( 0, 320). , , posInit 160. , ( ), posX1 160 0. , posX1 c 160 320. , , posInit 160, posX1 100, posThreshold . :
if (posInit > posX1) nextSlide(); else if (posInit < posX1) prevSlide();
, , click. posInit === posX1. , .
. JavaScript.
4. JavaScript
, , "" , , . , . , .
:
.slider-track transfrom: translate3d(Xpx, 0px, 0px);transfrom: translate3d(0px, 0px, 0px) style, ;style.transform match() ;swipeStart .slider-list touchstart mousedown;swipeStart document swipeAction swipeEnd touchmove (mousemove) touchend (mouseup) , ;posThreshold, slideIndex ;posThreshold , ;- -, .
 
.
. HTML- querySelector DOM, querySelector. , . .
let slider = document.querySelector('.slider'),
  sliderList = slider.querySelector('.slider-list'),
  sliderTrack = slider.querySelector('.slider-track'),
  slides = slider.querySelectorAll('.slide'),
  arrows = slider.querySelector('.slider-arrows'),
  prev = arrows.children[0],
  next = arrows.children[1],
  slideWidth = slides[0].offsetWidth,
  slideIndex = 0,
  posInit = 0,
  posX1 = 0,
  posX2 = 0,
  posFinal = 0,
  posThreshold = slideWidth * .35,
  trfRegExp = /[-0-9.]+(?=px)/,
  slide = function() {
    sliderTrack.style.transition = 'transform .5s';
    sliderTrack.style.transform = `translate3d(-${slideIndex * slideWidth}px, 0px, 0px)`;
    
    
    
    
    prev.classList.toggle('disabled', slideIndex === 0);
    next.classList.toggle('disabled', slideIndex === --slides.length);
  } ...
trfRegExp — , transform .slider-track.
event.clientX, touches — event.touches[0].clientX. event .. , getEvent. event.type touch touch event. .
getEvent = function() {
  return event.type.search('touch') !== -1 ? event.touches[0] : event;
  
},
getEvent = () => event.type.search('touch') !== -1 ? event.touches[0] : event,
swipeStart = function() {
  let evt = getEvent();
  
  posInit = posX1 = evt.clientX;
  
  
  sliderTrack.style.transition = '';
  
  document.addEventListener('touchmove', swipeAction);
  document.addEventListener('touchend', swipeEnd);
  document.addEventListener('mousemove', swipeAction);
  document.addEventListener('mouseup', swipeEnd);
},
swipeAction = function() {
  let evt = getEvent(),
    
    style = sliderTrack.style.transform,
    
    transform = +style.match(trfRegExp)[0];
  posX2 = posX1 - evt.clientX;
  posX1 = evt.clientX;
  sliderTrack.style.transform = `translate3d(${transform - posX2}px, 0px, 0px)`;
  
  
  
} ...
swipeAction:
transform. :
translate3d(0px, 0px, 0px) "px". transform. .
: [-0-9.]+(?=px), :
[-0-9.] — , "" " 0 9" "";+ — , 1 , , : 5, 101.10, -19, -12.5 ..;(?=px) — , , "px".
.slider-track , sliderTrack.style.transform = 'translate3d(0px, 0px, 0px)', swipeAction . :

( ) — swipeAction , .slider-track . swipeEnd , , :
swipeEnd = function() {
  
  posFinal = posInit - posX1;
  document.removeEventListener('touchmove', swipeAction);
  document.removeEventListener('mousemove', swipeAction);
  document.removeEventListener('touchend', swipeEnd);
  document.removeEventListener('mouseup', swipeEnd);
  
  if (Math.abs(posFinal) > posThreshold) {
    
    if (posInit < posX1) {
      slideIndex--;
    
    } else if (posInit > posX1) {
      slideIndex++;
    }
  }
  
  if (posInit !== posX1) {
    slide();
  }
};
touch drag , . : posFinal posThreshold, , , . Math.abs() .

. , .
arrows.addEventListener('click', function() {
  let target = event.target;
  if (target === next) {
    slideIndex++;
  } else if (target === prev) {
    slideIndex--;
  } else {
    return;
  }
  slide();
});
sliderTrack.style.transform = 'translate3d(0px, 0px, 0px)';
slider.addEventListener('touchstart', swipeStart);
slider.addEventListener('mousedown', swipeStart);
. .
. tocuh , drag -. , , :

Y, , ( ).

, , .

, . swipeAction, swipeStart 1 .
要解决此问题,您需要声明一个变量allowSwipe并调整对其的滑动禁止。
我不会详细描述。只需在下面布置此代码。
在此示例中,所有这些条件都已经满足。另外,为清楚起见,滑块上的光标也会更改。
完整代码(滑动,拖动,箭头)let slider = document.querySelector('.slider'),
  sliderList = slider.querySelector('.slider-list'),
  sliderTrack = slider.querySelector('.slider-track'),
  slides = slider.querySelectorAll('.slide'),
  arrows = slider.querySelector('.slider-arrows'),
  prev = arrows.children[0],
  next = arrows.children[1],
  slideWidth = slides[0].offsetWidth,
  slideIndex = 0,
  posInit = 0,
  posX1 = 0,
  posX2 = 0,
  posFinal = 0,
  posThreshold = slides[0].offsetWidth * 0.35,
  trfRegExp = /([-0-9.]+(?=px))/,
  getEvent = function() {
    return (event.type.search('touch') !== -1) ? event.touches[0] : event;
  },
  slide = function() {
    if (transition) {
      sliderTrack.style.transition = 'transform .5s';
    }
    sliderTrack.style.transform = `translate3d(-${slideIndex * slideWidth}px, 0px, 0px)`;
    prev.classList.toggle('disabled', slideIndex === 0);
    next.classList.toggle('disabled', slideIndex === --slides.length);
  },
  swipeStart = function() {
    let evt = getEvent();
    posInit = posX1 = evt.clientX;
    sliderTrack.style.transition = '';
    document.addEventListener('touchmove', swipeAction);
    document.addEventListener('mousemove', swipeAction);
    document.addEventListener('touchend', swipeEnd);
    document.addEventListener('mouseup', swipeEnd);
  },
  swipeAction = function() {
    let evt = getEvent(),
      style = sliderTrack.style.transform,
      transform = +style.match(trfRegExp)[0];
    posX2 = posX1 - evt.clientX;
    posX1 = evt.clientX;
    sliderTrack.style.transform = `translate3d(${transform - posX2}px, 0px, 0px)`;
  },
  swipeEnd = function() {
    posFinal = posInit - posX1;
    document.removeEventListener('touchmove', swipeAction);
    document.removeEventListener('mousemove', swipeAction);
    document.removeEventListener('touchend', swipeEnd);
    document.removeEventListener('mouseup', swipeEnd);
    if (Math.abs(posFinal) > posThreshold) {
      if (posInit < posX1) {
        slideIndex--;
      } else if (posInit > posX1) {
        slideIndex++;
      }
    }
    if (posInit !== posX1) {
      slide();
    }
  };
  sliderTrack.style.transform = 'translate3d(0px, 0px, 0px)';
  slider.addEventListener('touchstart', swipeStart);
  slider.addEventListener('mousedown', swipeStart);
  arrows.addEventListener('click', function() {
    let target = event.target;
    if (target === next) {
      slideIndex++;
    } else if (target === prev) {
      slideIndex--;
    } else {
      return;
    }
    slide();
  });
 最完整的代码let slider = document.querySelector('.slider'),
  sliderList = slider.querySelector('.slider-list'),
  sliderTrack = slider.querySelector('.slider-track'),
  slides = slider.querySelectorAll('.slide'),
  arrows = slider.querySelector('.slider-arrows'),
  prev = arrows.children[0],
  next = arrows.children[1],
  slideWidth = slides[0].offsetWidth,
  slideIndex = 0,
  posInit = 0,
  posX1 = 0,
  posX2 = 0,
  posY1 = 0,
  posY2 = 0,
  posFinal = 0,
  isSwipe = false,
  isScroll = false,
  allowSwipe = true,
  transition = true,
  nextTrf = 0,
  prevTrf = 0,
  lastTrf = --slides.length * slideWidth,
  posThreshold = slides[0].offsetWidth * 0.35,
  trfRegExp = /([-0-9.]+(?=px))/,
  getEvent = function() {
    return (event.type.search('touch') !== -1) ? event.touches[0] : event;
  },
  slide = function() {
    if (transition) {
      sliderTrack.style.transition = 'transform .5s';
    }
    sliderTrack.style.transform = `translate3d(-${slideIndex * slideWidth}px, 0px, 0px)`;
    prev.classList.toggle('disabled', slideIndex === 0);
    next.classList.toggle('disabled', slideIndex === --slides.length);
  },
  swipeStart = function() {
    let evt = getEvent();
    if (allowSwipe) {
      transition = true;
      nextTrf = (slideIndex + 1) * -slideWidth;
      prevTrf = (slideIndex - 1) * -slideWidth;
      posInit = posX1 = evt.clientX;
      posY1 = evt.clientY;
      sliderTrack.style.transition = '';
      document.addEventListener('touchmove', swipeAction);
      document.addEventListener('mousemove', swipeAction);
      document.addEventListener('touchend', swipeEnd);
      document.addEventListener('mouseup', swipeEnd);
      sliderList.classList.remove('grab');
      sliderList.classList.add('grabbing');
    }
  },
  swipeAction = function() {
    let evt = getEvent(),
      style = sliderTrack.style.transform,
      transform = +style.match(trfRegExp)[0];
    posX2 = posX1 - evt.clientX;
    posX1 = evt.clientX;
    posY2 = posY1 - evt.clientY;
    posY1 = evt.clientY;
    
    if (!isSwipe && !isScroll) {
      let posY = Math.abs(posY2);
      if (posY > 7 || posX2 === 0) {
        isScroll = true;
        allowSwipe = false;
      } else if (posY < 7) {
        isSwipe = true;
      }
    }
    if (isSwipe) {
      
      if (slideIndex === 0) {
        if (posInit < posX1) {
          setTransform(transform, 0);
          return;
        } else {
          allowSwipe = true;
        }
      }
      
      if (slideIndex === --slides.length) {
        if (posInit > posX1) {
          setTransform(transform, lastTrf);
          return;
        } else {
          allowSwipe = true;
        }
      }
      
      if (posInit > posX1 && transform < nextTrf || posInit < posX1 && transform > prevTrf) {
        reachEdge();
        return;
      }
      
      sliderTrack.style.transform = `translate3d(${transform - posX2}px, 0px, 0px)`;
    }
  },
  swipeEnd = function() {
    posFinal = posInit - posX1;
    isScroll = false;
    isSwipe = false;
    document.removeEventListener('touchmove', swipeAction);
    document.removeEventListener('mousemove', swipeAction);
    document.removeEventListener('touchend', swipeEnd);
    document.removeEventListener('mouseup', swipeEnd);
    sliderList.classList.add('grab');
    sliderList.classList.remove('grabbing');
    if (allowSwipe) {
      if (Math.abs(posFinal) > posThreshold) {
        if (posInit < posX1) {
          slideIndex--;
        } else if (posInit > posX1) {
          slideIndex++;
        }
      }
      if (posInit !== posX1) {
        allowSwipe = false;
        slide();
      } else {
        allowSwipe = true;
      }
    } else {
      allowSwipe = true;
    }
  },
  setTransform = function(transform, comapreTransform) {
    if (transform >= comapreTransform) {
      if (transform > comapreTransform) {
        sliderTrack.style.transform = `translate3d(${comapreTransform}px, 0px, 0px)`;
      }
    }
    allowSwipe = false;
  },
  reachEdge = function() {
    transition = false;
    swipeEnd();
    allowSwipe = true;
  };
sliderTrack.style.transform = 'translate3d(0px, 0px, 0px)';
sliderList.classList.add('grab');
sliderTrack.addEventListener('transitionend', () => allowSwipe = true);
slider.addEventListener('touchstart', swipeStart);
slider.addEventListener('mousedown', swipeStart);
arrows.addEventListener('click', function() {
  let target = event.target;
  if (target.classList.contains('next')) {
    slideIndex++;
  } else if (target.classList.contains('prev')) {
    slideIndex--;
  } else {
    return;
  }
  slide();
});
 代码库