Als ich anfing, JavaScript zu lernen, wollte ich unbedingt verstehen, wie Schieberegler funktionieren und hergestellt werden, die mit Wischen oder Maus umgedreht werden können, aber ich fand keine Materialien mit einer guten Erklärung für genau das, was ich brauche. Nach einiger Zeit gelang es mir, etwas Ähnliches zu tun. Und jetzt möchte ich einen Artikel darüber schreiben, damit andere Leute, die verstehen wollen, wie das alles funktioniert, und Berührungsereignisse für den Schieberegler (und nicht nur) machen, es einfacher machen, es herauszufinden. Ich werde versuchen, die Erklärungen in der richtigen Reihenfolge darzulegen und mit anschaulichen Beispielen zu unterstützen.
Ich betrachte mich nicht als großen Spezialisten für JavaScript. Es gibt immer etwas zu lernen. Wenn Sie also wissen, wie man einige Codefragmente besser / einfacher / effizienter schreibt, schreiben Sie unbedingt die Kommentare.
Inhalt:
- Welche Funktionen werden wir ausführen?
- HTML und CSS schreiben
- Wie wird es funktionieren?
- Javascript schreiben
- Gesamt
- Vollversionscode
Sie können sofort ein Beispiel sehen .
1. Welche Funktionen werden wir ausführen?
Schreiben wir mit 0 einen einfachen Schieberegler, der die folgenden Funktionen hat:
- Wir implementieren das Drehen von Folien durch Ziehen und Ziehen.
- Schieben Sie die Folien mit den Pfeiltasten.
- Sperren Sie die Pfeiltasten ← und → auf der ersten bzw. letzten Folie.
.
- , - , -, , , .. . . - , .
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-listpadding-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- posX1160.- swipeAction- posX1.
 
  
 
 - posX2—- posX1- event.clientX.- swipeAction, , - , " " = 161, 160 — 161 = -1, -1px. :
 
  
 
 - , , X, - posX2, . 0.5 10, ( , ́ , , ).
 
 
- , (- posFinal) "" (- posThreshold), .
 . . , :
 
 - posFinal=- posInit–- posX1( ,- swipeAction, , 200px, ,- posFinal100).
 
  
 
 
 - else- , .
 
 - posThreshold, ,- prev()- next().- posInit- posX1. 320px, ́ , 0px-320px ( 0, 320). , ,- posInit160. , ( ),- posX1160 0. ,- posX1c 160 320. , ,- posInit160,- posX1100,- 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 .
- Der Schieber kann "ergriffen" werden, wenn sich der Schieber noch nicht vollständig bewegt hat.
Um dieses Verhalten zu beheben, müssen Sie eine Variable deklarieren allowSwipeund das Swipe-Verbot anpassen.
Ich werde es nicht im Detail beschreiben. Legen Sie einfach diesen Code unten .
Und im Beispiel sind alle diese Bedingungen bereits erfüllt. Aus Gründen der Übersichtlichkeit ändert sich auch der Cursor auf dem Schieberegler.
Vollständiger Code (Wischen, Ziehen, Pfeile)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();
  });
 Der vollständigste Codelet 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();
});
 codepen.io