【问题标题】:JS DOM manipulation 'mouseleave' triggers unexpectedly in Safari browserJS DOM 操作“mouseleave”在 Safari 浏览器中意外触发
【发布时间】:2018-11-05 01:10:25
【问题描述】:

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

代码在以下环境中按预期工作:chrome、mozilla、edge、opera。但不是野生动物园!

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

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

【问题讨论】:

    标签: javascript browser safari dom-events dom-manipulation


    【解决方案1】:

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

    您的代码也可能会被简化。请参阅下面的 sn-p。希望对您有所帮助。

    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>

    【讨论】:

    • 我对事件处理程序'mouseenter', () =&gt; box.play = box.play 有点困惑,它应该做什么?如何更改此代码,以便当鼠标进入时它会快速更改第一张图像,然后每秒更改其他图像?
    • @JuozasRastenis,谢谢,我已经用老式风格重写了代码以避免混淆并满足您的要求when mouse enters it changes first image rapidly and then others each second。如果您有任何问题,请告诉我。
    猜你喜欢
    • 2015-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-10
    相关资源
    最近更新 更多