【问题标题】:jQuery: Highlight element under mouse cursor? [duplicate]jQuery:突出显示鼠标光标下的元素? [复制]
【发布时间】:2011-06-09 13:18:49
【问题描述】:

可能重复:
How to make this JavaScript much faster?

我正在尝试在 jQuery 中创建一个“元素选择器”,就像 Firebug 一样。基本上,我想突出显示用户鼠标下方的元素。到目前为止,这是我得到的,但效果不是很好:

$('*').mouseover(function (event) {
    var $this = $(this);
    $div.offset($this.offset()).width($this.width()).height($this.height());
    return false;
});


var $div = $('<div>')
    .css({ 'background-color': 'rgba(255,0,0,.5)', 'position': 'absolute', 'z-index': '65535' })
    .appendTo('body');

基本上,我将一个 div 注入到具有半透明背景的 DOM 中。然后我在每个元素上监听 mouseover 事件,然后移动 div 使其覆盖该元素。

现在,只要您将鼠标移到页面上,这只会使整个页面变红。我怎样才能让它更好地工作?

编辑: 很确定问题是,一旦我的鼠标接触到页面,主体就会被选中,然后当我四处移动鼠标时,没有任何时刻会通过高亮因为它凌驾于一切之上。


萤火虫

通过 Firebug 源代码挖掘,我发现了这个:

drawBoxModel: function(el)
{
    // avoid error when the element is not attached a document
    if (!el || !el.parentNode)
        return;

    var box = Firebug.browser.getElementBox(el);

    var windowSize = Firebug.browser.getWindowSize();
    var scrollPosition = Firebug.browser.getWindowScrollPosition();

    // element may be occluded by the chrome, when in frame mode
    var offsetHeight = Firebug.chrome.type == "frame" ? FirebugChrome.height : 0;

    // if element box is not inside the viewport, don't draw the box model
    if (box.top > scrollPosition.top + windowSize.height - offsetHeight ||
        box.left > scrollPosition.left + windowSize.width ||
        scrollPosition.top > box.top + box.height ||
        scrollPosition.left > box.left + box.width )
        return;

    var top = box.top;
    var left = box.left;
    var height = box.height;
    var width = box.width;

    var margin = Firebug.browser.getMeasurementBox(el, "margin");
    var padding = Firebug.browser.getMeasurementBox(el, "padding");
    var border = Firebug.browser.getMeasurementBox(el, "border");

    boxModelStyle.top = top - margin.top + "px";
    boxModelStyle.left = left - margin.left + "px";
    boxModelStyle.height = height + margin.top + margin.bottom + "px";
    boxModelStyle.width = width + margin.left + margin.right + "px";

    boxBorderStyle.top = margin.top + "px";
    boxBorderStyle.left = margin.left + "px";
    boxBorderStyle.height = height + "px";
    boxBorderStyle.width = width + "px";

    boxPaddingStyle.top = margin.top + border.top + "px";
    boxPaddingStyle.left = margin.left + border.left + "px";
    boxPaddingStyle.height = height - border.top - border.bottom + "px";
    boxPaddingStyle.width = width - border.left - border.right + "px";

    boxContentStyle.top = margin.top + border.top + padding.top + "px";
    boxContentStyle.left = margin.left + border.left + padding.left + "px";
    boxContentStyle.height = height - border.top - padding.top - padding.bottom - border.bottom + "px";
    boxContentStyle.width = width - border.left - padding.left - padding.right - border.right + "px";

    if (!boxModelVisible) this.showBoxModel();
},

hideBoxModel: function()
{
    if (!boxModelVisible) return;

    offlineFragment.appendChild(boxModel);
    boxModelVisible = false;
},

showBoxModel: function()
{
    if (boxModelVisible) return;

    if (outlineVisible) this.hideOutline();

    Firebug.browser.document.getElementsByTagName("body")[0].appendChild(boxModel);
    boxModelVisible = true;
}

看起来他们正在使用标准的 div + css 来绘制它......只需要弄清楚他们现在是如何处理事件的......(这个文件长 28K 行)

还有这个 sn-p,我猜它检索适当的对象....虽然我不知道如何。他们正在寻找一个“objectLink-element”类......我不知道这个“repObject”是什么。

onMouseMove: function(event)
{
    var target = event.srcElement || event.target;

    var object = getAncestorByClass(target, "objectLink-element");
    object = object ? object.repObject : null;

    if(object && instanceOf(object, "Element") && object.nodeType == 1)
    {
        if(object != lastHighlightedObject)
        {
            Firebug.Inspector.drawBoxModel(object);
            object = lastHighlightedObject;
        }
    }
    else
        Firebug.Inspector.hideBoxModel();

},

我在想,也许当为荧光笔节点触发 mousemove 或 mouseover 事件时,我可以以某种方式传递它?也许节点覆盖它...?


如果我在每个元素上方放置一个不可见元素,其 z-index 比我的荧光笔高,但给我的荧光笔一个比实际元素更高的 z-index...理论上,它应该可以工作。不可见元素会触发鼠标事件,但高亮效果看起来仍然像实际元素的覆盖。

这意味着我只是将 DOM 元素翻了一番,而且定位必须正确。 除非也许我只是“提升”荧光笔当前覆盖的元素?但这仍然可能是每个元素>。

【问题讨论】:

  • 在尝试做这样的事情时有一个令人讨厌的 catch-22。基本上,一旦你在鼠标下画了一些东西,由于鼠标悬停在一个元素上,鼠标实际上离开了原始元素,现在悬停在 new 元素上。
  • @Matt:那么我们如何解决这个问题呢? Firebug 是否不操纵 DOM 来渲染这些框,还是它有自己的渲染引擎?
  • 当您在 Firebug 中将鼠标悬停在网页上时,Firebug 会突出显示网页中的元素 - 这是单独的。或者那是累的想法?当您使用“点击检查”时,它只勾勒出元素,这可能是问题的症结所在 - Firebug 可以绘制 4 个单独的元素,一个用于框的每个边缘,在这种情况下,我提到的 catch-22 是根本不是问题。
  • +1 用于挖掘 Firebug 源代码 - 我打算这样做。

标签: jquery


【解决方案1】:

所有这些答案都太复杂了......简单的解决方案:

Javascript:

prevElement = null;
document.addEventListener('mousemove',
    function(e){
        var elem = e.target || e.srcElement;
        if (prevElement!= null) {prevElement.classList.remove("mouseOn");}
        elem.classList.add("mouseOn");
        prevElement = elem;
    },true);

CSS:

.mouseOn{
  background-color: #bcd5eb !important;
  outline: 2px solid #5166bb !important;
}

【讨论】:

    【解决方案2】:

    修改大卫的回答,使其正确地恢复背景颜色后记...

    $('body *').live('mouseover mouseout', function(event) {
        if (event.type == 'mouseover') {
            $(this).data('bgcolor', $(this).css('background-color'));
            $(this).css('background-color','rgba(255,0,0,.5)');
        } else {
            $(this).css('background-color', $(this).data('bgcolor'));
        }
        return false;
    });
    

    【讨论】:

      【解决方案3】:

      我可以建议一种替代方法吗?

      如何简单地将background-color 分配给页面的所有子元素,然后在hover() 上调整that 元素的background-color 以增加其对比度?

      $('html').children().css('background-color','rgba(0,0,0,0.2)');
      $('body').children().hover(
          function(){
              $(this).css('background-color','#fff');
          },
          function(){
              $(this).css('background-color','rgba(0,0,0,0.2)');
          });
      

      JS Fiddle demo.

      【讨论】:

      • 有可能。如果找不到解决方案,我可能不得不采用这种方法,但这真的困扰着我,因为我知道必须有办法做到这一点。
      【解决方案4】:

      ► This 不那么烦躁,但如果不先将鼠标完全关闭所述父元素,它就无法检测到从父元素移动到其子元素。

      var $div = $('<div id="highlighter">').css({
          'background-color': 'rgba(255,0,0,.5)',
          'position': 'absolute',
          'z-index': '65535'
      }).hide().prependTo('body');
      
      var $highlit;
      
      $('*').live('mousemove', function(event) {
          if (this.nodeName === 'HTML' || this.nodeName === 'BODY')
          {
              $div.hide();
              return false;
          }
          var $this = this.id === 'highligher' ? $highlit : $(this),
      
              x = event.pageX,
              y = event.pageY,
      
              width = $this.width(),
              height = $this.height(),
              offset = $this.offset(),
      
              minX = offset.left,
              minY = offset.top,
              maxX = minX + width,
              maxY = minY + height;
      
          if (this.id === 'highlighter')
          {
              if (minX <= x && x <= maxX
                  && minY <= y && y <= maxY)
              {
                  // nada
              }
              else
              {
                  $div.hide();
              }
          }
          else
          {
              $highlit = $this;
              $div.offset(offset).width($this.width()).height($this.height()).show();
          }
          return false;
      });
      

      希望这有助于让事情顺利进行。您可能可以调整我写的内容以使用document.elementFromPoint(x, y) 来检查鼠标是否已移动到当前突出显示的元素的子元素中。我现在还不够清醒,无法弄清楚这一点。

      或者,如果概述与突出显示一样好,您可以尝试我在对原始问题的评论中提到的方法。在当前悬停的元素周围绘制 4 个 div* - 这是轮廓框每个边缘的一个 div。您和您的实际内容之间不再有绘图元素!


      *我敢打赌,document.elementFromPoint(x, y) 将使您在此处更容易获取鼠标下的元素。

      【讨论】:

      • 到达那里...仍然需要一些工作。我会看看我能做什么。
      【解决方案5】:

      鼠标悬停时整个页面变红的原因是您的代码匹配了body 元素的mouseover 事件。您可以通过仅选择 body 的子级来阻止这种情况发生。

      $('body *').bind( //...
      

      您会在包含大量元素的页面上遇到性能问题,但因为 bind 将为每个匹配的元素附加一个侦听器。尝试查看 jQuery 的事件委托 API(.delegate()http://api.jquery.com/delegate/),它允许您侦听传播到根元素的事件并且也适用于鼠标事件。

      【讨论】:

      • 这并不能真正解决问题(使用body *),只是将问题转移到更深的元素。见马特的评论。暂时还不太担心性能,我会采取任何有效的方法。
      • 另外,我不使用 live() 或 delegate() 的原因是因为将来的元素将被包括在内......也就是说,我不希望它开始选择自己(这是为什么我在绑定事件后附加它)。
      • 您是否尝试检查传递给您的回调的事件对象是否为 currentTarget?如果 currentTarget 是你的高亮 div,那么你什么都不做。
      • 我什么都不做也没关系,它仍然会阻止 real 元素接收事件。 (但是是的,只要我能解决其他问题,我就可以使用live()...)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-24
      • 1970-01-01
      相关资源
      最近更新 更多