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-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 .
- 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 allowSwipe
und 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