JS DOM 操作 'mouseleave' 在 Safari 浏览器中意外触发

JS DOM manipulation 'mouseleave' triggers unexpectedly in Safari browser

编辑:'mouseleave'事件不断被触发,尽管鼠标没有离开元素。

代码按预期工作:chrome、mozilla、edge、opera。但不是野生动物园!

我有一个普通的 JavaScript 解决方案,当鼠标悬停在父元素上时,它每 1000 毫秒更改一次图像。包装器内可以有任意数量的图像,这应该仍然有效。为了更清楚,javascript 为每个图像添加 "hidden" class 并将其从轮到要显示的图像中删除。 (代码在 fiddle 中)。

在 Safari 中,它似乎卡在交换第 2-3 张图像中。我使用了错误的 dom 操作方法吗?我怎样才能找到错误?

问题介绍: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>

您需要查看 mouseleave 事件的 relatedTarget,因为每次显示的图像更改时都会发生 mouseentermouseleave

您的代码也可能会得到简化。请参阅下面的代码段。希望对你有帮助。

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>