防止鼠标移动对elementFromPoint的攻击

Prevent mousemove fire upon elementFromPoint

本文关键字:elementFromPoint 攻击 移动 鼠标      更新时间:2024-01-08

演示:http://jsfiddle.net/2FWZD/

这是jsfiddle代码,因为它迫使我添加代码:

$(document).ready(function () {
    $('.test').on('mousemove', function (e) {
        counter++;
        $('.counter').text(counter);
        $(this).hide();
        // Comment out the following line and counter will stop increasing
        document.elementFromPoint(e.clientX, e.clientY);
        $(this).show();
    });
});

这种情况发生在chrome中,是否有任何方法可以防止这种情况或elementFromPoint的替代方法?

Bug详细信息如下:https://code.google.com/p/chromium/issues/detail?id=333623


编辑1:

我只想指出,虽然答案是对jsfiddle演示的破解,但它实际上并没有解决我所面临的根本问题。

我正在使用Leap Motion在一个网站上模拟鼠标,该网站发送模拟的mousedown和mouseup事件以及鼠标移动。我使用画布在所有内容的顶部绘制光标,并使用此处显示的技术访问画布下方的元素。这样做后,鼠标移动是在真实的鼠标位置触发的,而不是我的模拟鼠标,这实际上给了我一些奇怪的问题。

这不是FireFox的问题。


编辑2:

问题解决了。请参阅答案。使用hide()之外的其他隐藏方法似乎可以在不触发的情况下工作

只保留最后一个位置,如下所示:

var counter = 0;
var last='';
$(document).ready(function () {
    $('.test').on('mousemove', function (e) {
        var cur=e.screenX+':'+e.screenY;
        if (cur == last) return;
        last = cur;
        counter++;
        $('.counter').text(counter);
        $(this).hide();
        // Comment out the following line and counter will stop increasing
        document.elementFromPoint(e.clientX, e.clientY);
        $(this).show();
    });
});

另一种方法似乎是通过使用css使元素"不可见"来隐藏元素:

var counter = 0;
$(document).ready(function () {
    $('.test').on('mousemove', function (e) {
        counter++;
        $('.counter').text(counter);
        $(this).addClass('hidden');
        // Comment out the following line and counter will stop increasing
        console.log(document.elementFromPoint(e.clientX, e.clientY));
        $(this).removeClass('hidden');
    });
});

css:

.test.hidden {
    overflow: hidden;
    width: 0;
    height: 0;
    margin: 0;
    padding: 0;
}

http://jsfiddle.net/2FWZD/10/

elementFromPoint()将返回特定坐标的元素。在这种情况下,指针/光标下的元素。在示例代码中,elementFromPoint()函数返回<html>,因为.test是隐藏的。出于某种原因,这导致Chrome认为鼠标在移动。但是,您可以使用querySelectorAll(":hover")而不是elementFromPoint()

jsfiddle演示

var counter = 0;
$(document).ready(function () {
    $('.test').not( "body" ).on('mousemove', function (e) {
        counter++;
        $('.counter').text(counter);
        $(this).hide();
        // Comment out the following line and counter will stop increasing
        var el=document.querySelectorAll( ":hover" ); //el = html not .test because it is hidden
        console.log(el);
        $(this).show();
    });
});

以下是问题发生的可能原因:

浏览器进行优化,尽可能少地重新绘制,以提供更流畅的查看体验。这意味着,在可能的情况下,像这样的块

$(this).hide();
$(this).show();

在可能的情况下被优化为无操作。然而,当在两个操作之间强制重绘时,情况并非如此,例如,您的代码就是这样

$(this).hide();
document.elementFromPoint(e.clientX, e.clientY);
$(this).show();

或者,有时被用作黑客攻击,以避免在不需要时进行优化

$(this).hide();
this.offsetHeight;
$(this).show();

在某些情况下,再次显示元素似乎会触发Chrome上的mousemove

简而言之

不要使用$(element).hide()。Chrome有问题(成为我们的新IE6)。

当尝试执行getElementFromPoint 时,您不想显示.test-元素,而不是仅仅分发css自己

请参阅jsFiddle 中的解决方案

长版本

Chrome目前无法处理CSS中的"display:none",将重新绘制总元素。这将引发mousemove事件,从而使其成为一个永恒的循环。

不使用display:none,您也可以只将"height"设置为零,这将对选择正确的元素具有相同的效果。基于此,我制作了一个函数fastDraw

.hide()变为fastDraw
function fastDraw($box, show){
    if(show){
        $box.css({'height': $box.data('height')});
    } else {
        $box.data('height', $box.height());
        $box.css({'height': 0});
    }
}

现在你得到相同的结果

fastDraw($box); //hides the element by setting the height zero
var element = document.elementFromPoint(e.clientX, e.clientY); //fetches the element
fastDraw($box, true); //return it back to the previous height

优化

由于您正在使用mouseMove事件,它将被调用很多次,最好尽可能少地调用。我已经重构了一些东西,所以它会做更少的计算。

相关文章:
  • 没有找到相关文章