Манипуляции с JS DOM «mouseleave» неожиданно запускаются в браузере Safari - PullRequest
0 голосов
/ 03 ноября 2018

EDIT: событие mouseleave постоянно вызывается, хотя мышь не покидает элемент.

Код работает так, как задумано: chrome, mozilla, edge, opera. Но не сафари!

У меня есть ванильное решение JavaScript, которое меняет изображения каждые 1000 мс, когда мышь наводится на родительский элемент. В оболочке может быть любое количество изображений, и это все равно должно работать. Чтобы быть более понятным, javascript добавляет «скрытый» класс для каждого изображения и удаляет его из списка, который должен отображаться. (Код в скрипке).

В сафари, кажется, застрял, меняя 2-3-е изображение. Я использую неправильный подход дом-манипуляции? Как я могу найти ошибку?

Представление задачи: 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>

1 Ответ

0 голосов
/ 04 ноября 2018

Вам нужно посмотреть на relatedTarget из mouseleave события, так как mouseenter и mouseleave происходят каждый раз, когда изменяется отображаемое изображение.

Также ваш код может быть упрощен. Смотрите фрагмент ниже. Надеюсь, это поможет.

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