2011-01-15 16 views
18

Duplicar posible:
How to make this JavaScript much faster?jQuery: elemento resaltado debajo del cursor del mouse?

estoy tratando de crear un "selector de elemento" en jQuery, tiene como Firebug. Básicamente, quiero resaltar el elemento debajo del mouse del usuario. Esto es lo que tengo hasta ahora, pero no está funcionando muy bien:

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

Básicamente, estoy inyectando un div en el DOM que tiene un fondo semitransparente. Luego escucho el evento mouseover en cada elemento, luego muevo el div para que cubra ese elemento.

En este momento, esto solo hace que toda la página se vuelva roja tan pronto como mueva el mouse sobre la página. ¿Cómo puedo hacer que esto funcione mejor?

Editar: seguro de que el problema es que tan pronto como el ratón toca a la página, el cuerpo se ha seleccionado, y luego como muevo el ratón alrededor, ninguno de los momentos van pasando a través de la highligher porque su overtop de todo.


Firebug

de excavación a través del código fuente de Firebug, me encontré con esto:

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

parece que están usando un div estándar + CSS para dibujar ..... solo tiene para averiguar cómo están manejando los eventos ahora ... (este archivo tiene una longitud de 28K)

También hay este fragmento, que creo que recupera el objeto apropiado ... aunque no puedo entender cómo . Están buscando una clase "objectLink-element" ... y no tengo idea de qué es este "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(); 

}, 

estoy pensando que tal vez cuando se dispara el evento MouseMove o encima del ratón para el nodo rotulador puedo pasar de alguna manera a lo largo de su lugar? Tal vez al nodo está cubriendo ...?


Si coloco un elemento invisible por encima de todos los elementos con un alto índice z que mi marcador, pero doy mi rotulador un mayor índice z de los elementos reales ... en teoría, debería funcionar. Los elementos invisibles dispararán el evento del mouse, pero el efecto de resaltado aún se verá como un sobretiro de los elementos reales.

Esto significa que acabo de duplicar los elementos DOM, y el posicionamiento tiene que ser correcto. A menos que tal vez solo "levante" los elementos que el resaltador está cubriendo actualmente? Pero eso aún podría ser cada elemento>. < ¡Alguien me ayude!

+3

Hay un desagradable catch-22 cuando intentas hacer cosas como esta. Básicamente, tan pronto como dibuja algo debajo del mouse, como resultado del mouse sobre un elemento, el mouse realmente abandona el elemento original y ahora está sobrevolando el _new_ one. –

+0

@Matt: Bueno, ¿cómo solucionamos esto entonces? ¿Firebug no manipula el DOM para renderizar esos cuadros, o tiene su propio motor de representación? – mpen

+1

Firebug resalta los elementos en una página web cuando pasas el mouse sobre ellos en Firebug, que está ** separado **. ¿O está cansado, piensas? Cuando utilizas el "clic para inspeccionar" solo se delinean los elementos, lo que puede ser el quid de la cuestión: Firebug podría dibujar 4 elementos separados, uno para cada borde de la caja, en cuyo caso, el catch-22 que mencioné isn No es un problema en absoluto. –

Respuesta

1

La razón por la que toda la página se pone roja tan pronto como pasa el mouse es que su código coincide con un evento mouseover para el elemento body. Puede evitar que esto ocurra seleccionando solo niños de body.

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

Usted va a golpear los problemas de rendimiento en una página con un gran número de elementos, aunque ya que se unen adjuntará un oyente para cada elemento emparejado sola. Intente echar un vistazo a la API de delegación de eventos de jQuery (.delegate(), http://api.jquery.com/delegate/) que le permite escuchar los eventos que se propagan hasta un elemento raíz y funciona también para los eventos del mouse.

+0

Eso realmente no soluciona el problema (usando 'body *'), que simplemente mueve el problema a un elemento ligeramente más profundo. Vea el comentario de Matt. No estoy muy preocupado por el rendimiento todavía, tomaré todo lo que funcione. – mpen

+0

Además, la razón por la que no estoy usando live() o delegate() es porque entonces se incluirían los elementos futuros ... es decir, no quiero que comience a seleccionarse a sí mismo (razón por la cual lo anexé después de enlazarlo) el evento). – mpen

+0

¿Ha intentado verificar el objeto de evento pasado a su devolución de llamada para el destino actual? Si el actualTarget es tu div destacado, entonces no puedes hacer nada. – andrewle

1

► This es un poco menos inquietos, pero no pueden detectar movimiento a partir de un elemento padre de uno de sus hijos sin mover primero el ratón completamente fuera dicho progenitor.

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

Afortunadamente eso ayuda a que la pelota ruede. Probablemente podría modificar lo que he escrito para usar document.elementFromPoint(x, y) para comprobar si el mouse se ha movido o no a un elemento secundario del elemento actualmente resaltado. No estoy lo suficientemente despierto como para resolver esto ahora mismo.

O bien, si el delinear es tan bueno como destacarlo, puede probar el enfoque que mencioné en mi comentario a su pregunta original. Dibuje 4 divs alrededor del elemento que se encuentra actualmente * - ese es un div para cada borde del cuadro de contorno. ¡No más elementos de dibujo entre usted y su contenido real!


* Apostaría que document.elementFromPoint(x, y) hará llegar el elemento bajo el puntero del ratón mucho más fácil aquí.

+0

Llegar allí ... todavía necesita algo de trabajo. Veré lo que puedo hacer. – mpen

2

¿Puedo sugerir un enfoque alternativo?

¿Qué hay de simplemente asignar un background-color a todos los elementos secundarios de la página, y luego, en hover(), ajustar el background-color de que elemento para aumentar su contraste?

$('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 posible. Puede que tenga que seguir este enfoque si no puedo encontrar una solución, pero esto * realmente * me molesta porque sé que tiene que haber una manera de hacerlo. – mpen

3

Modificar la respuesta de David para que revierte adecuadamente los epílogos de color de fondo ...

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

Todas estas respuestas son demasiado complicados ... Solución sencilla:

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