Reputation: 265
EDIT: 'mouseleave' event is constantly being triggered, although the mouse does not leave the element.
Code works as intended in: chrome, mozilla, edge, opera. But not safari!
I have a vanilla JavaScript solution that changes images every 1000ms when mouse hovered on parent element. There can be any amount of images inside wrapper and this should still work. To be more clear, javascript adds "hidden" class for every image and removes it from the one who's turn is to be displayed. (Code is in fiddle).
In safari it seems to be stuck swapping 2-3rd image. Am I using wrong dom-manipulation approach? How can I find the error?
Problem presentation: https://jsfiddle.net/pcwudrmc/65236/
let imageInt = 0;
let timeOut;
let imagesWrapper = document.querySelectorAll('.items-box__item');
// Events for when mouse enters/leaves
imagesWrapper.forEach(el => {
el.addEventListener('mouseenter', () => startAnim(el));
el.addEventListener('mouseleave', () => stopanim(el));
});
// DOM Manipulation functions
function changeImages(el) {
imageInt += 1;
if (imageInt === el.children[0].children.length) {
// reset to 0 after going through all images
imageInt = 0;
}
for (let i = 0; i < el.children[0].children.length; i++) {
// Adds "hidden" class to ALL of the images for a product
el.children[0].children[i].classList.add('hidden');
}
// Removes "hidden" class for one
el.children[0].children[imageInt].classList.remove('hidden');
// changeImage calls itself again after 1 second, if hovered
timeOut = setTimeout(changeImages.bind(null, el), 1000);
}
function changeBack(el) {
for (let i = 0; i < el.children[0].children.length; i++) {
// Adds "hidden" class to ALL of the images for a product
el.children[0].children[i].classList.add('hidden');
}
// Removes "hidden" class for the first image of the item
el.children[0].children[0].classList.remove('hidden');
}
startAnim = element => { changeImages(element) }
stopanim = element => {
changeBack(element);
clearTimeout(timeOut);
imageInt = 0;
}
.items-box__item {
width: 300px;
height: 300px;
}
.items-box__item--main-image {
object-fit: contain;
width: 90%;
height: 265px;
}
.hidden {
display: none;
}
<h3>Hover on pic and hold mouse</h3>
<div class="items-box__item">
<a href="/">
<img class="items-box__item--main-image" src="https://res.cloudinary.com/keystone-demo/image/upload/c_limit,h_300,w_300/v1525948251/yrllszgndxzlydbycewc.jpg"/>
<img class="items-box__item--main-image hidden" src="https://res.cloudinary.com/keystone-demo/image/upload/c_limit,h_300,w_300/v1525948251/e96i5zbvxxuxsdczbh9d.jpg"/>
<img class="items-box__item--main-image hidden" src="https://res.cloudinary.com/keystone-demo/image/upload/c_limit,h_300,w_300/v1525948252/boaqfs3yuc4r7mvhsqqu.jpg"/>
</a>
</div>
Upvotes: 0
Views: 446
Reputation: 18378
You need to look at relatedTarget
of mouseleave
event, as both mouseenter
and mouseleave
happen every time the displayed image changes.
Also your code might be simplified. See the snippet below. Hope it helps.
const play = (box) => {
while (!box.classList.contains('items-box__item')) box = box.parentElement;
var img = box.querySelector('.show');
img.classList.remove('show');
(img.nextElementSibling || box.firstElementChild).classList.add('show');
}
const stop = ({target: box, relatedTarget: rt}) => {
while (!box.classList.contains('items-box__item')) box = box.parentElement;
while (rt != box && rt) rt = rt.parentElement;
if (rt === box) return;
box.querySelector('.show').classList.remove('show');
box.firstElementChild.classList.add('show');
box.play = clearInterval(box.play);
}
[...document.querySelectorAll('.items-box__item')]
.forEach((box) => {
box.addEventListener(
'mouseenter',
function() {
if (box.play) return;
play(box);
box.play = setInterval(() => play(box), 1000);
}
);
box.addEventListener('mouseleave', stop);
});
.items-box__item {
display: block;
width: 300px;
height: 300px;
}
.items-box__item img {
object-fit: contain;
width: 90%;
height: 265px;
display: none;
}
img.show {
display: initial
}
<h3>Hover on pic and hold mouse</h3>
<a class="items-box__item" href="/">
<img class="show" src="https://res.cloudinary.com/keystone-demo/image/upload/c_limit,h_300,w_300/v1525948251/yrllszgndxzlydbycewc.jpg">
<img src="https://res.cloudinary.com/keystone-demo/image/upload/c_limit,h_300,w_300/v1525948251/e96i5zbvxxuxsdczbh9d.jpg">
<img src="https://res.cloudinary.com/keystone-demo/image/upload/c_limit,h_300,w_300/v1525948252/boaqfs3yuc4r7mvhsqqu.jpg">
</a>
Upvotes: 1