如何使用叠加层有效地突出显示鼠标光标下的元素? [英] How do I efficiently highlight element under mouse cursor with an overlay?

查看:15
本文介绍了如何使用叠加层有效地突出显示鼠标光标下的元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

仍在尝试回答这个问题,我想我终于找到了一个解决方案,但运行速度太慢.

var $div = $('

').css({ 'border': '1px 纯红色', 'position': 'absolute', 'z-index': '65535' }).appendTo('body');$('body *').live('mousemove', function(e) {var topElement = null;$('body *').each(function() {if(this == $div[0]) 返回真;var $elem = $(this);var pos = $elem.offset();var width = $elem.width();var height = $elem.height();if(e.pageX > pos.left && e.pageY > pos.top&&e.pageX <(pos.left + 宽度) &&e.pageY <(pos.top + 高度)) {var zIndex = document.defaultView.getComputedStyle(this, null).getPropertyValue('z-index');if(zIndex == 'auto') zIndex = $elem.parents().length;if(topElement == null || zIndex > topElement.zIndex) {顶部元素 = {'节点':$elem,'zIndex': zIndex};}}});if(topElement != null ) {var $elem = topElement.node;$div.offset($elem.offset()).width($elem.width()).height($elem.height());}});

它基本上遍历页面上的所有元素并找到光标下方的最顶部元素.

有没有什么办法可以使用四叉树或其他东西来分割页面,以便循环运行得更快?

解决方案

有没有什么办法可以使用四叉树或其他东西来分割页面,以便循环运行得更快?

退后一步,意识到问题有多小,你尝试的越难,你将使用的答案越复杂.

现在您需要做的是为突出显示创建 4 个元素.它们将形成一个空方块,因此您的鼠标事件可以自由触发.这类似于我制作的这个 叠加示例.

区别在于你只需要四个元素(没有调整大小标记),并且这4个框的大小和位置有点不同(模仿红色边框).然后你可以在你的事件处理程序中使用 event.target ,因为它默认获取真正的最顶层元素.

另一种方法是隐藏exra元素,得到elementFromPoint,计算然后放回去.

我可以告诉你,它们比光还快.连爱因斯坦都会同意:)

1.) elementFromPoint 叠加/边框 - [Demo1] FF 需要 v3.0+

var box = $("

").css({显示:无",位置:绝对",zIndex: 65000, 背景:"rgba(255, 0, 0, .3)"}).appendTo("body");var mouseX, mouseY, target, lastTarget;//如果您需要支持旧浏览器,请使用 requestAnimationFrame polyfill//例如:https://gist.github.com/paulirish/1579671window.requestAnimationFrame(function frame() {window.requestAnimationFrame(frame);if (target && target.className === "outer") {box.hide();目标 = document.elementFromPoint(mouseX, mouseY);}box.show();if (target === lastTarget) 返回;lastTarget = 目标;var $target = $(target);var offset = $target.offset();box.css({宽度:$target.outerWidth() - 1,高度:$target.outerHeight() - 1,左:偏移量.左,顶部:偏移量.top});});$("body").mousemove(function (e) {mouseX = e.clientX;鼠标Y = e.clientY;目标 = e.target;});

<小时>

2.) 鼠标悬停边框 - [Demo2]

var box = new Overlay();$("body").mouseover(function(e){var el = $(e.target);var offset = el.offset();box.render(el.outerWidth(), el.outerHeight(), offset.left, offset.top);});/*** 该对象封装了叠加层的元素和动作.*/功能叠加(宽度,高度,左,上){this.width = this.height = this.left = this.top = 0;//外部父级var outer = $("<div class='outer'/>").appendTo("body");//红线(方框)var topbox = $("<div/>").css("height", 1).appendTo(outer);var bottombox = $("<div/>").css("height", 1).appendTo(outer);var leftbox = $("<div/>").css("width", 1).appendTo(outer);var rightbox = $("<div/>").css("width", 1).appendTo(outer);//不要把它算作一个真正的元素外层鼠标悬停(功能(){外层隐藏();});/*** 公共接口*/this.resize = function resize(width, height, left, top) {如果(宽度!= null)this.width = 宽度;如果(高度!= null)this.height = 高度;如果(左!= null)this.left = 左;如果(顶部!= null)this.top = 顶部;};this.show = 函数显示(){外层显示();};this.hide = 函数隐藏(){外层隐藏();};this.render = function render(width, height, left, top) {this.resize(width, height, left, top);顶盒.css({顶部:this.top,左:this.left,宽度:this.width});底盒.css({顶部:this.top + this.height - 1,左:this.left,宽度:this.width});leftbox.css({顶部:this.top,左:this.left,高度:this.height});rightbox.css({顶部:this.top,左:this.left + this.width - 1,高度:this.height});this.show();};//初始渲染 [可选]//this.render(width, height, left, top);}

Still trying to answer this question, and I think I finally found a solution, but it runs too slow.

var $div = $('<div>')
    .css({ 'border': '1px solid red', 'position': 'absolute', 'z-index': '65535' })
    .appendTo('body');

$('body *').live('mousemove', function(e) {
    var topElement = null;
    $('body *').each(function() {
        if(this == $div[0]) return true;
        var $elem = $(this);
        var pos = $elem.offset();
        var width = $elem.width();
        var height = $elem.height();
        if(e.pageX > pos.left && e.pageY > pos.top
            && e.pageX < (pos.left + width) && e.pageY < (pos.top + height)) {
            var zIndex = document.defaultView.getComputedStyle(this, null).getPropertyValue('z-index');
            if(zIndex == 'auto') zIndex = $elem.parents().length;
            if(topElement == null || zIndex > topElement.zIndex) {
                topElement = {
                    'node': $elem,
                    'zIndex': zIndex
                };
            }

        }
    });
    if(topElement != null ) {
        var $elem = topElement.node;
        $div.offset($elem.offset()).width($elem.width()).height($elem.height());
    }
});

It basically loops through all the elements on the page and finds the top-most element beneath the cursor.

Is there maybe some way I could use a quad-tree or something and segment the page so the loop runs faster?

解决方案

Is there maybe some way I could use a quad-tree or something and segment the page so the loop runs faster?

Just step back a bit, realize how small the problem is, and that the harder your try the more complicated answer you will use.

Now what you need to do is to create 4 elements for the highlighting. They will form an empty square, and so your mouse events are free to fire. This is similar to this overlay example I've made.

The difference is that you only need the four elements (no resize markers), and that the size and position of the 4 boxes are a bit different (to mimick the red border). Then you can use event.target in your event handler, because it gets the real topmost element by default.

Another approach is to hide the exra element, get elementFromPoint, calculate then put it back.

They're faster than light, I can tell you. Even Einstein would agree :)

1.) elementFromPoint overlay/borders - [Demo1] FF needs v3.0+

var box = $("<div class='outer' />").css({
  display: "none", position: "absolute", 
  zIndex: 65000, background:"rgba(255, 0, 0, .3)"
}).appendTo("body");

var mouseX, mouseY, target, lastTarget;

// in case you need to support older browsers use a requestAnimationFrame polyfill
// e.g: https://gist.github.com/paulirish/1579671
window.requestAnimationFrame(function frame() {
  window.requestAnimationFrame(frame);
    if (target && target.className === "outer") {
        box.hide();
        target = document.elementFromPoint(mouseX, mouseY);
    }
    box.show();   

    if (target === lastTarget) return;

    lastTarget = target;
    var $target = $(target);
    var offset = $target.offset();
    box.css({
        width:  $target.outerWidth()  - 1, 
        height: $target.outerHeight() - 1, 
        left:   offset.left, 
        top:    offset.top 
    });
});

$("body").mousemove(function (e) {
    mouseX = e.clientX;
    mouseY = e.clientY;
    target = e.target;
});


2.) mouseover borders - [Demo2]

var box = new Overlay();

$("body").mouseover(function(e){
  var el = $(e.target);
  var offset = el.offset();
  box.render(el.outerWidth(), el.outerHeight(), offset.left, offset.top);
});​

/**
 * This object encapsulates the elements and actions of the overlay.
 */
function Overlay(width, height, left, top) {

    this.width = this.height = this.left = this.top = 0;

    // outer parent
    var outer = $("<div class='outer' />").appendTo("body");

    // red lines (boxes)
    var topbox    = $("<div />").css("height", 1).appendTo(outer);
    var bottombox = $("<div />").css("height", 1).appendTo(outer);  
    var leftbox   = $("<div />").css("width",  1).appendTo(outer);
    var rightbox  = $("<div />").css("width",  1).appendTo(outer);

    // don't count it as a real element
    outer.mouseover(function(){ 
        outer.hide(); 
    });    

    /**
     * Public interface
     */

    this.resize = function resize(width, height, left, top) {
      if (width != null)
        this.width = width;
      if (height != null)
        this.height = height;
      if (left != null)
        this.left = left;
      if (top != null)
        this.top = top;      
    };

    this.show = function show() {
       outer.show();
    };

    this.hide = function hide() {
       outer.hide();
    };     

    this.render = function render(width, height, left, top) {

        this.resize(width, height, left, top);

        topbox.css({
          top:   this.top,
          left:  this.left,
          width: this.width
        });
        bottombox.css({
          top:   this.top + this.height - 1,
          left:  this.left,
          width: this.width
        });
        leftbox.css({
          top:    this.top, 
          left:   this.left, 
          height: this.height
        });
        rightbox.css({
          top:    this.top, 
          left:   this.left + this.width - 1, 
          height: this.height  
        });

        this.show();
    };      

    // initial rendering [optional]
    // this.render(width, height, left, top);
}

这篇关于如何使用叠加层有效地突出显示鼠标光标下的元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆