Detectar alterações de conteúdo de elemento com jQuery

113

change() A função funciona e detecta alterações nos elementos do formulário, mas há uma maneira de detectar quando o conteúdo de um elemento DOM foi alterado?

Isso não funciona, a menos que #contentseja um elemento de formulário

$("#content").change( function(){
    // do something
});

Eu quero que isso seja acionado ao fazer algo como:

$("#content").html('something');

Além disso, html()ou a append()função não tem um retorno de chamada.

Alguma sugestão?

Elzo Valugi
fonte
velha pergunta eu sei, mas verifique minha resposta para uma solução elegante stackoverflow.com/a/23826615/744975
Andrew Atkinson

Respostas:

26

Esses são eventos de mutação .

Não usei APIs de eventos de mutação no jQuery, mas uma pesquisa rápida me levou a este projeto no GitHub. Desconheço a maturidade do projeto.

jrharshath
fonte
17
Este plugin de eventos de mutação não funcionará, porque ele apenas conecta os eventos aos métodos de mutação jQuery. Eles são disparados quando o próprio jQuery tenta alterar os elementos, mas não quando os elementos são alterados de fora do jQuery. Eles não observam as mudanças no documento. Em vez disso, verifique este pequeno plugin: stackoverflow.com/questions/3233991/jquery-watch-div/…
Sebastián Grignoli
10
Pesquisar e postar um link para uma biblioteca que você nunca experimentou não é extremamente útil. (Comentando porque fui solicitado a votar contra ele.)
Pare de caluniar Monica Cellio
27
Os eventos de mutação foram descontinuados ; não os use.
Brock Adams
A alternativa para eventos de mutação parece ser MutationObservers .
WoodrowShigeru,
69

Sei que esta postagem tem um ano, mas gostaria de fornecer uma abordagem de solução diferente para aqueles que têm um problema semelhante:

  1. O evento de mudança do jQuery é usado apenas em campos de entrada do usuário porque se algo mais for manipulado (por exemplo, um div), essa manipulação virá do código. Portanto, descubra onde ocorre a manipulação e, em seguida, adicione o que for necessário.

  2. Mas se isso não for possível por algum motivo (você está usando um plugin complicado ou não consegue encontrar nenhuma possibilidade de "retorno de chamada"), então a abordagem jQuery que eu sugiro é:

    uma. Para manipulação DOM simples, use o encadeamento e travessia jQuery,$("#content").html('something').end().find(whatever)....

    b. Se você gostaria de fazer outra coisa, use jQuery's bindcom eventos personalizados etriggerHandler

    $("#content").html('something').triggerHandler('customAction');
    
    $('#content').unbind().bind('customAction', function(event, data) {
       //Custom-action
    });

Aqui está um link para o manipulador de gatilho jQuery: http://api.jquery.com/triggerHandler/

Kyle
fonte
1
Pensamento final. embora isso deva ser bastante abrangente acima: você pode atualizar o valor de um campo de entrada oculto com o do #content html e, em seguida, vincular o evento de mudança ao campo de entrada oculto :) muitas opções
Kyle
7
+1 "Descubra onde ocorre a manipulação e, a seguir, adicione o que for necessário." Corrigido meu problema em 2 segundos sem quaisquer hacks / plugins :)
Hartley Brody
A única alteração que sugiro aqui é que bindestá esperando seu manipulador retornar a bool.
Serj Sagan
15

O navegador não disparará o evento onchange para os <div>elementos.

Acho que o raciocínio por trás disso é que esses elementos não mudarão a menos que modificados por javascript. Se você já tiver que modificar o elemento por conta própria (em vez de o usuário fazê-lo), poderá simplesmente chamar o código de acompanhamento apropriado ao mesmo tempo que modifica o elemento, assim:

 $("#content").html('something').each(function() { });

Você também pode disparar manualmente um evento como este:

 $("#content").html('something').change();

Se nenhuma dessas soluções funcionar para sua situação, você poderia fornecer mais informações sobre o que você está especificamente tentando realizar?

TM.
fonte
11
Isso pressupõe que você escreveu todo o javascript, o que pode não ser o caso.
Myster,
OBRIGADO!!!! Isso só me ajudou a resolver um problema que eu estava enfrentando há 6 horas.
Jordan Parmer
Exatamente o que eu precisava.
smac89
15

e http://jsbin.com/esepal/2

$(document).bind("DOMSubtreeModified",function(){
  console.log($('body').width() + ' x '+$('body').height());
})

Este evento foi descontinuado em favor da API Mutation Observer

FDisk
fonte
1
não é uma má ideia, embora eu me pergunte quanto apoio tem isso. developer.mozilla.org/en/DOM/DOM_event_reference/…
Elzo Valugi
Como você monitora um elemento específico para mudanças? Atualmente, o documento monitora a página inteira.
Patoshi パ ト シ
3

Não é estritamente uma resposta jQuery - mas é útil mencionar para depuração.

No Firebug, você pode clicar com o botão direito em um elemento na árvore DOM e configurar 'Break on Attribute Change':

Elemento clique com o botão direito no Firebug com Break on Attribute Change destacado

Quando um atributo é alterado em um script, a janela de depuração aparece e você pode rastrear o que está acontecendo. Também há uma opção para inserção e remoção de elemento abaixo (obscurecido de forma inútil pelo pop-up na captura de tela).

John Reid
fonte
1
Isso é útil, mas não exatamente o que ele estava pedindo. Isso detectará coisas como quando uma classe muda ou quando um atributo de estilo é adicionado ou alterado. Ele não verificará quando o conteúdo no interior do nó muda. Por exemplo, se algum javascript em algum lugar mudar um nó de <span> hello </span> para <span> World </span>, isso não o detectará
Joshua Soileau
2

Estou desenvolvendo uma pequena biblioteca JS chamada mutabor ( https://github.com/eskat0n/mutabor ), que visa simplificar o uso de eventos de mutação DOM. Veja demo.html para exemplos.

Eskat0n
fonte
1

Freqüentemente, uma maneira simples e eficaz de fazer isso é controlar quando e onde você está modificando o DOM.

Você pode fazer isso criando uma função central que é sempre responsável por modificar o DOM. Em seguida, você faz qualquer limpeza necessária no elemento modificado de dentro desta função.

Em um aplicativo recente, não precisei de ação imediata, então usei um retorno de chamada para a função load () portátil, para adicionar uma classe a quaisquer elementos modificados e, em seguida, atualizei todos os elementos modificados a cada poucos segundos com um temporizador setInterval.

$($location).load("my URL", "", $location.addClass("dommodified"));

Então você pode lidar com isso como quiser - por exemplo

setInterval("handlemodifiedstuff();", 3000); 
function handlemodifiedstuff()
{
    $(".dommodified").each(function(){/* Do stuff with $(this) */});
}
Antony Carthy
fonte
3
Isso pressupõe que você escreveu todo o javascript, o que pode não ser o caso.
Myster,
1

Você pode adicionar uma opção de retorno de chamada à função html (ou qualquer):

$.fn.oldHtml = $.fn.html;
$.fn.html = function(html,fn){
  fn = fn || function(){};
  var result =  this.oldHtml(html);
  fn();
  return result;
};
$('body').html(11,function(){alert("haha");});

Demonstração aqui.

Você faz a mudança em algum elemento, e não o elemento é forçado a mudar por algo que você precisa capturar.


fonte
Tive que resolver esse problema hoje. Não consegui editar o código que realmente chamava html () porque está em uma biblioteca de terceiros. Uma versão modificada disso era perfeita para mim. Eu fiz isso: $ .fn.oldHtml = $ .fn.html (); $ .fn.html = function (e) {var result = this.oldHtml (e); this.trigger ('afterHtmlChange', e);} Agora posso vincular quaisquer eventos que eu queira ao evento afterHtmlChange recém-criado em qualquer elemento, que será acionado sempre que algo chamar html () fn de jQuery.
Daniel Howard
Opa, pequeno erro. Fn em meu comentário acima deve ser: function (e) {var result = this.oldHtml (e); this.trigger ('afterHtmlChange', e); resultado de retorno;}
Daniel Howard
0

Eu escrevi um snippet que verificará a alteração de um elemento em um evento.

Portanto, se você estiver usando um código javascript de terceiros ou algo assim e precisar saber quando algo aparece ou muda quando você clica, você pode.

Para o snippet abaixo, digamos que você precise saber quando o conteúdo de uma tabela muda depois que você clica em um botão.

$('.button').live('click', function() {

            var tableHtml = $('#table > tbody').html();
            var timeout = window.setInterval(function(){

                if (tableHtml != $('#table > tbody').
                    console.log('no change');
                } else {
                    console.log('table changed!');
                    clearInterval(timeout);
                }

            }, 10);
        });

Pseudo-código:

  • Depois de clicar em um botão
  • o html do elemento que você espera alterar é capturado
  • então verificamos continuamente o html do elemento
  • quando descobrimos que o html é diferente, paramos a verificação
Andrew Atkinson
fonte
0

Podemos fazer isso usando eventos de mutação . De acordo com www.w3.org, o módulo de evento de mutação é projetado para permitir a notificação de qualquer alteração na estrutura de um documento, incluindo modificações de atributo e de texto. Para mais detalhes EVENTOS DE MUTAÇÃO

Por exemplo :

$("body").on('DOMSubtreeModified', "#content", function() {
    alert('Content Modified'); // do something
});
Sanchit Gupta
fonte
Isso foi descontinuado por um tempo. Deve-se usar Mutation Observers (mesmo conceito)
Carles Alcolea
-3

Não é possível, eu acredito que tenha um evento de conteúdo alterado, mas certamente não é o x-browser

Devo dizer que não é possível sem algum intervalo desagradável roncando no fundo!

quadrado vermelho
fonte
21
nada é impossível!
jrharshath