Quand j'ai commencé à apprendre JavaScript, je voulais vraiment comprendre comment fonctionnent les curseurs qui peuvent être retournés avec un glissement ou une souris, mais je n'ai pas trouvé de matériel avec une bonne explication de ce dont j'avais besoin. Après un certain temps, j'ai réussi à faire quelque chose de similaire. Et maintenant, je veux écrire un article à ce sujet, afin que d'autres personnes qui veulent comprendre comment tout cela fonctionne et créer des événements tactiles pour le curseur (et pas seulement) facilitent la compréhension. Je vais essayer de mettre en ordre et de soutenir les explications avec des exemples illustratifs.
Je ne me considère pas comme un grand spécialiste du JavaScript, il y a toujours quelque chose à apprendre, donc si vous savez comment écrire des fragments de code mieux / plus facilement / plus efficacement, assurez-vous d'écrire dans les commentaires.
Contenu:
- Quelle fonctionnalité ferons-nous?
- Écriture HTML et CSS
- Comment ça va marcher?
- Écriture javascript
- Total
- Code de version complète
Vous pouvez immédiatement voir un exemple .
1. Quelles fonctionnalités ferons-nous?
Écrivons avec 0 un simple curseur qui aura les fonctions suivantes:
- nous implémentons le toucher et le glissement en retournant les diapositives;
- changer de diapos à l'aide des touches fléchées;
- verrouillez les touches fléchées ← et → sur la première et la dernière diapositive, respectivement.
.
- , - , -, , , .. . . - , .
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 .
- Le curseur peut être "saisi" lorsque la diapositive n'a pas encore fini de bouger.
Pour corriger ce problème, vous devez déclarer une variable allowSwipe
et ajuster l'interdiction de glisser dessus.
Je ne le décrirai pas en détail. Présentez simplement ce code ci-dessous .
Et dans l' exemple, toutes ces conditions seront déjà réalisées. De plus, pour plus de clarté, le curseur sur le curseur change.
Code complet (glisser, glisser, flèches)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();
});
Le code le plus completlet 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