2012-06-11 10 views
11

En este momento estoy tratando de encontrar una manera de detectar cuando un elemento HTML ha cambiado.Necesito una nueva forma de detectar si ha habido un cambio en un elemento HTML

actualmente estoy tratando:

var a, b; 
setInterval(function() { 
    a = $('#chat').text(); 
}, 150); 
setInterval(function() { 
    b = $('#chat').text(); 
    if (a !== b) { 
     alert("There has been a new message."); 
    } 
}, 200);​ 

Lo que hago es cada 150 milisegundos puedo comprobar el código HTML de #chat y luego cada 200 segundos puedo comprobar el HTML de nuevo y luego comprobar si la variable a no lo hace igual a la variable b ellos en el futuro voy a hacer algo con eso, pero por ahora solo estoy alerta algo.

Se puede ver en vivo aquí: http://jsfiddle.net/MT47W/

Obviamente esta manera no está funcionando y no es muy precisa en absoluto. ¿Hay algo mejor/diferente que hacer/lograr esto?

Gracias por cualquier ayuda, he estado tratando de descubrir cómo hacerlo mejor durante aproximadamente una semana pero no puedo encontrar una solución para esto y espero haber publicado este problema en el lugar correcto, y en el momento correcto.

Respuesta

6

Utilice un var para almacenar el elemento actual text a continuación, comprobar en contra de ella en un setInverval y actualizar el var para almacenar la corriente text después de comprobar:

var a = $('#chat').text(); 
setInterval(function() { 
    if (a !== $('#chat').text()) { //checks the stored text against the current 
     alert("There has been a new message."); //do your stuff 
    } 
    a = $('#chat').text(); //updates the global var to store the current text 
}, 150); //define your interval time, every 0.15 seconds in this case 

Fiddle

Usted puede también almacenar la valor en el .data() del elemento para evitar el uso de globales.

Ejemplo usando .data():

$('#chat').data('curr_text', $('#chat').text()); 
setInterval(function() { 
    if ($('#chat').data('curr_text') !== $('#chat').text()) { 
     alert("There has been a new message."); 
    } 
    $('#chat').data('curr_text', $('#chat').text()); 
}, 150); 

Fiddle

Otro enfoque, para ahorrar memoria del cliente, que sólo puede almacenar el número de niños div es tu elemento #chat tiene:

$('#chat').data('n_msgs', $('#chat').children().length); 
setInterval(function() { 
    if ($('#chat').data('n_msgs') !== $('#chat').children().length) { 
     alert("There has been a new message."); 
    } 
    $('#chat').data('n_msgs', $('#chat').children().length); 
}, 150); 

Fiddle


EDIT: Aquí es mi adición muy final, con un DOM mutation event listener:

$('#chat').on('DOMNodeInserted', function() { 
    alert("There has been a new message."); 
}); 

Fiddle (no probado en IE < 8)

Nota: Como se señala en los comentarios, aunque los eventos de mutación aún se admiten, se clasifican como deprecated by W3C debido a la pérdida de rendimiento y algunas incompatibilidades entre diferentes navegadores, por lo tanto, se sugiere utilizar una de las soluciones anteriores y solo usar eventos de mutación DOM cuando no hay otra alternativa.

+1

Podría estar equivocado, pero estoy bastante seguro de que escuchar eventos DOM no está muy bien soportado y eliminado de las últimas especificaciones por completo. – zatatatata

+0

@VahurRoosimaa, podría estar equivocado, pero jQuery trabaja principalmente en el evento DOM escuchando la delegación de eventos y veo que últimamente se usa ampliamente en las respuestas. Ahora, si trae algún problema de compatibilidad, cualquiera de las revisiones anteriores también funcionará. =] ¿O quisiste decir, los eventos de mutación DOM específicamente? –

+1

Wow muchas gracias. Nunca escuché acerca de: DOMNodeInserted y no estoy seguro si eso sería bien soportado como dijo Vahur, así que creo que usaré el segundo método. Pero gracias por todas estas formas. Pero también pensé en usar datos de solo obtener la longitud de los niños en #chat. ¡Bueno, aprendo algo nuevo todos los días! :) – Shawn31313

2

Simplemente revisando el último chat mejoraría la eficiencia y también haría lo que usted quisiera.La única forma de que no funcione es si la misma persona envía el mismo mensaje dos veces, lo que probablemente no ocurra.

espero que esto funcionaría:

var lastMessage = $('#chat .body').last().text(); 
    function checkMessages(){ 
     var newLastMessage = $('#chat .body').last().text(); 
     if(lastMessage !== newLastMessage && $('#chat .body').last().length > 0){ 
      //message has changed 
      alert("There has been a new message."); 
      lastMessage = $('#chat .body').last().text(); 
     } 
     setTimeout(function(){checkMessages();},1000); 
    } 
    checkMessages(); 

Js Fiddle

+1

¿Qué sucede si el mismo usuario publica el mismo mensaje dos veces? Su función no se activa para los remitentes de correo no deseado: P –

+0

Buen punto. Sin embargo, estoy bastante seguro de que el usuario no querrá recibir notificaciones continuas de los spammers. Además, realmente no importará porque el "nuevo mensaje" es básicamente el mismo mensaje. : D –

+1

¿Qué navegadores no son compatibles con setInterval? – zatatatata

1

Uso crc32 o hash MD5 para comprobar si los datos han cambiado. Simplemente obtenga el contenido html del div que desea verificar, córtalo como una cadena con crc32 o md5 y obtendrá una cadena que representará ese contenido. Use una marca de tiempo oculta, etc. para asegurarse de que varios mensajes de un usuario obtengan un hash diferente. Si haces esto en una devolución de llamada setInterval, deberías estar bien.

0

Aunque no es muy recomendable, también es posible utilizar Paul Irish's Duck punching método para atar en función de agregación de jQuery - si se sabe con certeza que la función append es cómo se va a agregar contenido (demo):

(function($) { 
    // store original reference to the method 
    var _old = $.fn.append; 
    $.fn.append = function(arg) { 
     // append as usual 
     _old.apply(this, arguments); 

     // do your own checking here 
     // "this" is a jQuery object 
     if (this[0].id === "chat") { 
      alert('there is a new message!'); 
     } 
     return this; 
    }; 

})(jQuery); 

Con este método, no se necesitan bucles de sincronización.

Cuestiones relacionadas