【问题标题】:mousemove triggers more often with console open?mousemove 在控制台打开时更频繁地触发?
【发布时间】:2022-01-01 07:13:42
【问题描述】:

我遇到了一些奇怪的事情,但我不确定这是故意的还是导致它的原因。

我正在试验一些 JavaScript,当用户在屏幕上移动鼠标时循环一组图像。我为此使用 jQuery mousemove。这是一个小提琴:https://jsfiddle.net/sy35dzeh/1/

我遇到的行为是鼠标移动时的某种油门。我希望移动每个像素以增加 pixelCount 变量。但是,在较长的扫描中移动鼠标时,似乎迭代达到了极限。这会导致在缓慢移动鼠标时计数器增加得更快,因为每次添加的“像素”更多。我知道这可能是mousemove 的工作方式,但最重要的是,它在打开开发者工具时表现不同。

当我在 Chrome 中打开开发者工具并尝试再次移动鼠标时,迭代速度要快得多。这是我想要的行为,当鼠标移动较慢时迭代变慢,而鼠标移动得更快时迭代变快。

这里有一段视频说明了不同之处: https://streamable.com/okqql3

知道为什么我打开控制台时它会有所不同吗?知道如何让鼠标移动以我希望的方式影响迭代(比如打开开发者工具时)?

【问题讨论】:

  • 如果您从图片中完全删除 jquery,我希望它更准确为 example here
  • 使用 vanilla JavaScript 后仍然有相同的行为:jsfiddle.net/jgzkt5b6
  • 哦,对不起,我之前快速阅读了您的问题!你说的是坐标跳跃!这是设计上的硬件限制,您需要改用something like this。很抱歉!
  • 别担心!我可以想象这是“按设计”完成的事情,或者至少是由mousemove 事件的限制引起的。然而奇怪的是,当打开开发人员工具时,鼠标并没有跳过,至少没有跳过那么多。您发送的链接适用于 C#。但也许在 JavaScript 中有类似的方法可以做到这一点。
  • 啊,对不起,哈哈,今天的多任务处理太多了,基本上它只是没有足够快地报告它,所以如果你移动它的速度足够快,你就会错过更新的值,因为它没有足够快地发出更新的值因为在事件冒泡的时候,坐标可能已经改变了。特别是在 javascript 浏览器级别。对于使用 javascript UIEvent 界面的那个问题,我没有答案。

标签: javascript


【解决方案1】:

我使用event.getCoalescedEvents() 修复了它,它得到了缺失的“中间”动作。 请注意,您需要收听“pointermove”,我正在这样做。

 this.canvas.addEventListener('pointermove', this.onMouseMove.bind(this), { passive: true });

 onMouseMove(event) {
    const events = event.getCoalescedEvents();
    for (let i = 0; i < events.length; i++) this.onMovement(events[i]);
  }

  onMovement(event) {
    // standard processing
  }

【讨论】:

  • 我撤回我的赏金
  • 一个评论是,我不确定对 getCoalescedEvents 的支持范围有多大。似乎它至少不适用于 iOS 14.8.1 的 Safari,试试这个例子:omwnk.codesandbox.io,但在我的场景中这没什么大不了的。
【解决方案2】:

Mousemove event 不是为每个像素调用的,但它的工作原理是这样的 - the browser periodically checks the cursor position 并注意到变化,生成 mousemove 事件。 因此,在您的情况下,最好不要从事件触发器的数量中计算像素,但需要坐标变化的差异。

另外,在调用mousemove 时,我不建议使用缓慢而繁重的同步函数,值得将它们单独添加到Event Loop(至少通过setTimeout)。

下面我对你指定的例子稍作修改:

let imageIndex = 1
let pixelCount = 0
let $targetElement = $(".mouse-image");
let divisions = 50

let pixelThreshold = Math.floor($(window).width() / divisions)

$(document).ready(function() {
  $targetElement.eq(0).addClass("is-active");
})

$(window).on("resize", function() {
  pixelThreshold = Math.floor($(window).width() / divisions)
})
let prevX = null;
let prevY = null;
let timeout = null;
$(document).on("mouseenter", function(ev) {
  prevX = ev.clientX;
  prevY = ev.clientY;
})

$(document).on("mouseleave", function(ev) {
  prevX = null;
  prevY = null;
})

$(document).on("mousemove", function(ev) {
  const posX = ev.clientX;
  const posY = ev.clientY;
  const deltaX = (!prevX) ? 1 : Math.abs(posX - prevX);
  const deltaY = (!prevY) ? 1 : Math.abs(posY - prevY);
  prevX = posX;
  prevY = posY;
  pixelCount += (deltaX + deltaY);

  if (pixelCount > pixelThreshold) {
    pixelCount = 0;
    changeImage();
    clearTimeout(timeout);
    timeout = setTimeout(changeImage, 20);
  }
  $(".debug").text(`${pixelCount}, ${pixelThreshold}`)
})

function changeImage() {
  imageIndex++
  if (imageIndex >= $targetElement.length) {
    imageIndex = 0;
  }
  $targetElement.removeClass("is-active");
  $targetElement.eq(imageIndex).addClass("is-active");
}
html {
  font-size: 100%
}

body {
  width: 100%;
  height: 100%;
}

*,
:after,
:before {
  padding: 0;
  margin: 0;
  -webkit-box-sizing: border-box;
  box-sizing: border-box
}

.image-container {
  width: 100vw;
  height: 100vh
}

.mouse-image {
  display: none;
  -o-object-fit: cover;
  object-fit: cover;
  width: 100%;
  height: 100%
}

.mouse-image.is-active {
  display: block
}

.debug {
  position: fixed;
  top: 0;
  right: 0;
  background-color: #fff;
  z-index: 999999999;
  font-size: 4rem
}

.wrapper {
  position: fixed;
  top: 0;
  left: 0;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  width: 100vw;
  height: 100vh;
  z-index: 9999
}

.wrapper .trigger {
  width: 100%
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="debug"></div>
<div class="image-container">
  <img class="mouse-image" src="https://www.airtasker.com/blog/wp-content/uploads/2018/01/Puppy-toilet-training-1200x675.jpg" alt="">
  <img class="mouse-image" src="https://awl.org.au/sites/default/files/styles/page_hero/public/hero/puppy-1221791_1920.jpg?itok=SLa7BGdj" alt="">
  <img class="mouse-image" src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcT69ZsF7GXUMrNLc1AOvNjXXoZWmNyA61fAqg&usqp=CAU" alt="">
  <img class="mouse-image" src="https://www.bil-jac.com/media/ww5kq5u4/puppy.jpg?anchor=center&mode=crop&width=1024&height=512" alt="">
  <img class="mouse-image" src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcRWeA5-zFa86-P6aDd5NUERS6ay9isKpgkDiQ&usqp=CAU" alt="">
</div>

【讨论】:

  • 这并不能解释为什么 Chrome 开发工具打开时会更流畅
  • @MickaelFM,正如我所说,浏览器会定期使用 mousemove 轮询坐标。这个频率受Event Loop 的加载程度的影响(渲染和更新 DOM 直接影响这一点)。通过打开 WebInspector,您可以减少视口,这直接影响页面和元素的呈现。在正常情况下,这些都是小事,但使用 mousemove 会很明显。
  • @MickaelFM,如果您需要使用mousemove进行同步计算,请转至WebWorker。例如,如果您需要在鼠标移动时在 Canvas 中执行任何重要的渲染计算,请在单独的 WebWorker 中使用 OffscreenCanvas
猜你喜欢
  • 2023-04-02
  • 1970-01-01
  • 2017-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-29
  • 1970-01-01
相关资源
最近更新 更多