2011-01-15 12 views
18

Mögliche Duplizieren:
How to make this JavaScript much faster?jQuery: Markieren Sie das Element unter dem Mauszeiger?

Ich versuche, ein "Element-Picker" in jQuery zu erstellen, wie Firebug hat. Grundsätzlich möchte ich das Element unter der Maus des Benutzers hervorheben. Hier ist, was ich so weit gekommen, aber es funktioniert nicht sehr gut:

$('*').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'); 

Grundsätzlich bin ich ein Div in die DOM Injektion, die einen halbtransparenten Hintergrund hat. Dann höre ich für jedes Element nach dem mouseover-Ereignis und verschiebe dann das div so, dass es dieses Element abdeckt.

Im Moment wird nur die ganze Seite rot, sobald Sie die Maus über die Seite bewegen. Wie kann ich das schöner arbeiten lassen?

Edit: Ziemlich sicher, dass das Problem ist, dass, sobald die Maus die Seite berührt, wird der Körper ausgewählt, und dann, als ich um meine Maus bewegen, keiner der Momente erhalten durch die highligher, weil seine overtop bestandener alles.


Firebug

Graben durch Firebug Quellcode, fand ich diese:

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; 
} 

Sieht aus wie sie ein Standard-div + CSS verwenden zu ziehen ..... nur haben um herauszufinden, wie sie die Ereignisse jetzt behandeln ... (diese Datei ist 28K Zeilen lang)

Es gibt auch dieses Snippet, das ich denke, das passende Objekt abgerufen .... obwohl ich nicht herausfinden, wie . Sie suchen nach einer Klasse "objectLink-element" ... und ich habe keine Ahnung was dieses "repObject" ist.

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(); 

}, 

Ich denke, dass vielleicht, wenn die mousemove- oder Mouseover-Ereignis ausgelöst wird für den Textmarker Knoten ich es irgendwie entlang stattdessen passieren kann? Vielleicht zum Knoten deckt es ...?


Wenn ich mit einem höheren Z-Index als mein Textmarker, ein unsichtbares Element über jedes Element positionieren, aber meinem Highlighter einen höheren Z-Index als die tatsächlichen Elemente geben ... theoretisch soll es funktionieren. Die unsichtbaren Elemente lösen das Mausereignis aus, aber der Hervorhebungseffekt sieht immer noch wie der Überhang der tatsächlichen Elemente aus.

Das bedeutet, ich habe nur die DOM-Elemente verdoppelt, und die Positionierung muss korrekt sein. Es sei denn vielleicht "life" ich nur die Elemente, die der Textmarker gerade bedeckt ?? Aber das könnte immer noch jedes Element sein. < Jemand hilf mir!

+3

Es gibt einen fiesen Catch-22, wenn man versucht, sowas zu machen. Sobald Sie nun etwas unter die Maus zeichnen, während die Maus über einem Element schwebt, verlässt die Maus tatsächlich das ursprüngliche Element und schwebt nun über dem neuen Element. –

+0

@Matt: Nun, wie schaffen wir das dann? Behandelt Firebug das DOM nicht, um diese Felder zu rendern, oder hat es eine eigene Rendering-Engine? – mpen

+1

Firebug hebt Elemente in einer Webseite hervor, wenn Sie in Firebug mit der Maus darüber fahren - was ** separat ** ist. Oder ist das müde? Wenn Sie das "Klicken zum Inspizieren" verwenden, werden nur die Elemente umrissen, die den Kern der Sache ausmachen könnten - Firebug könnte 4 separate Elemente zeichnen, eines für jeden Rand der Box, in welchem ​​Fall die Catch-22, die ich erwähnt habe, isn ist Das ist überhaupt kein Problem. –

Antwort

1

Der Grund, dass die ganze Seite rot wird, sobald Sie mit der Maus über sind, ist, dass Ihr Code ein mouseover Ereignis für das body Element entspricht. Sie können dies verhindern, indem Sie nur die untergeordneten Elemente body auswählen.

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

Sie werden Performance-Probleme auf einer Seite mit einer großen Anzahl von Elementen getroffen, obwohl seit binden einen Zuhörer für jeden einzelnen abgestimmt Element anhängen wird. Werfen Sie einen Blick in die jQuery-Ereignisdelegation api (.delegate(), http://api.jquery.com/delegate/), mit der Sie nach Ereignissen suchen können, die sich bis zu einem Wurzelelement ausbreiten, und auch für Mausereignisse arbeiten.

+0

Das behebt das Problem nicht wirklich (mit 'body *'), das verschiebt das Problem einfach auf ein etwas tieferes Element. Siehe Matts Kommentar. Ich mache mir noch keine Gedanken über die Leistung, ich nehme alles, was funktioniert. – mpen

+0

Der Grund, warum ich nicht live() oder delegate() verwende, ist, weil dann zukünftige Elemente enthalten wären ... nämlich, dass ich nicht anfangen soll, sich selbst auszuwählen (weshalb ich es angehängt habe, nachdem ich gebunden habe) das Ereignis). – mpen

+0

Haben Sie versucht, das Ereignisobjekt zu überprüfen, das an Ihren Callback für das currentTarget übergeben wurde? Wenn das currentTarget Ihr Hervorhebungs-Div ist, könnten Sie einfach nichts tun. – andrewle

1

► This ist ein bisschen weniger zappelig, aber es kann nicht ohne Bewegen der Maus vollständig aus die Eltern von einem übergeordneten Element zu einem seiner Kinder detect bewegen.

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; 
}); 

Hoffentlich hilft das den Ball ins Rollen. Sie könnten wahrscheinlich zwicken, was ich geschrieben habe, um document.elementFromPoint(x, y) zu verwenden, um zu überprüfen, ob die Maus in ein untergeordnetes Element des aktuell markierten Elements verschoben wurde. Ich bin nicht wach genug, um das jetzt herauszufinden.

Alternativ, wenn Outlining ist so gut wie Hervorhebung für Sie, könnten Sie versuchen, die Vorgehensweise, die ich in meinem Kommentar zu Ihrer ursprünglichen Frage erwähnt. Zeichne 4 divs um das aktuell schwebende Element * - das ist ein div für jede Kante der Outline-Box. Keine Zeichnungselemente mehr zwischen Ihnen und Ihrem eigentlichen Inhalt!


* Ich würde wetten, dass document.elementFromPoint(x, y) das Element unter der Maus immer viel einfacher hier machen.

+0

Das Hinkommen ... braucht noch etwas Arbeit. Ich sehe was ich tun kann. – mpen

2

Kann ich einen alternativen Ansatz vorschlagen?

Wie wäre es einfach ein background-color auf alle untergeordneten Elemente der Seite zuweisen und dann auf hover(), stellen Sie die background-color von dass Element den Kontrast zu erhöhen?

$('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.

+0

Es ist möglich. Ich muss vielleicht mit diesem Ansatz fortfahren, wenn ich keine Lösung finden kann, aber das nervt mich wirklich, weil ich weiß, dass es einen Weg geben muss, es zu tun. – mpen

3

Um Davids Antwort zu ändern, so dass es richtig die Nachworte Hintergrundfarbe wechselt ...

$('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; 
}); 
25

Alle diese Antworten sind zu kompliziert ... Einfache Lösung:

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; 
} 
Verwandte Themen