Existe um ouvinte de alteração de JavaScript / jQuery DOM?
402
Basicamente, quero que um script seja executado quando o conteúdo de uma DIValteração. Como os scripts são separados (script de conteúdo na extensão do Chrome e no script da página da web), preciso de uma maneira simplesmente observar as alterações no estado do DOM. Eu poderia configurar a pesquisa, mas isso parece desleixado.
Por um longo tempo, os eventos de mutação DOM3 foram a melhor solução disponível, mas foram preteridos por motivos de desempenho. Os observadores de mutação DOM4 substituem os eventos de mutação DOM3 descontinuados. Atualmente, eles são implementados em navegadores modernos como MutationObserver(ou como prefixo do fornecedor WebKitMutationObservernas versões antigas do Chrome):
MutationObserver= window.MutationObserver|| window.WebKitMutationObserver;var observer =newMutationObserver(function(mutations, observer){// fired when a mutation occurs
console.log(mutations, observer);// ...});// define what element should be observed by the observer// and what types of mutations trigger the callback
observer.observe(document,{
subtree:true,
attributes:true//...});
Este exemplo escuta as alterações do DOM em documenttoda a sua subárvore e aciona as alterações nos atributos do elemento, bem como as mudanças estruturais. A especificação de rascunho possui uma lista completa de propriedades válidas do ouvinte de mutação :
childList
Defina como truese as mutações nos filhos do alvo devem ser observadas.
atributos
Defina como truese as mutações nos atributos do alvo devem ser observadas.
characterData
Defina como truese as mutações nos dados do alvo devem ser observadas.
subárvore
Defina como truese as mutações não apenas atingirem o alvo, mas também os descendentes do alvo devem ser observados.
attributeOldValue
Defina como trueif attributescomo true e o valor do atributo do destino antes que a mutação precise ser registrada.
characterDataOldValue
Defina como trueif characterDatacomo true e os dados do destino antes que a mutação precise ser registrada.
attributeFilter
Defina como uma lista de nomes locais de atributos (sem espaço para nome) se nem todas as mutações de atributo precisarem ser observadas.
(Esta lista está atualizada em abril de 2014; você pode verificar a especificação para quaisquer alterações.)
@AshrafBashir Vejo o exemplo funcionando bem no Firefox 19.0.2: vejo o ([{}])logon no console, que mostra o esperado MutationRecordquando clico nele. Verifique novamente, pois pode ter sido uma falha técnica temporária no JSFiddle. Ainda não testei no IE, pois não tenho o IE 10, que atualmente é a única versão para suportar eventos de mutação.
Apsillers
11
Acabei de publicar uma resposta que funciona no IE10 + e principalmente qualquer outra coisa.
naugtur
11
A especificação parece não ter uma caixa verde que lista as opções de observador de mutação por mais tempo. Ele lista as opções na seção 5.3.1 e as descreve apenas um pouco mais abaixo disso.
LS
2
@LS Obrigado, atualizei o link, removi a parte verde da caixa e editei a lista inteira em minha resposta (apenas no caso de futuras rotações de links).
Esta resposta está agora obsoleta. Veja a resposta dos apsillers .
Como se trata de uma extensão do Chrome, você também pode usar o evento DOM padrão - DOMSubtreeModified. Veja o suporte para este evento nos navegadores. É suportado no Chrome desde 1.0.
Ainda funciona se você estiver criando extensões do Chrome. inestimável.
concept47
49
Muitos sites usam o AJAX para adicionar / mostrar / alterar conteúdo dinamicamente. Às vezes, é usado em vez da navegação no site; portanto, o URL atual é alterado de forma programática e, nesse caso, os scripts de conteúdo não são executados automaticamente pelo navegador, pois a página não é obtida totalmente do servidor remoto.
Métodos JS comuns para detectar alterações de página disponíveis em um script de conteúdo .
MutationObserver ( docs ) para detectar literalmente alterações no DOM:
Verificação periódica do DOM via setInterval :
Obviamente, isso funcionará apenas nos casos em que você esperar que um elemento específico identificado por seu ID / seletor apareça e não permitirá que você detecte universalmente novo conteúdo adicionado dinamicamente, a menos que invente algum tipo de impressão digital o conteúdo existente.
document.head.appendChild(document.createElement('script')).text ='('+function(){// injected DOM script is not a content script anymore, // it can modify objects and functions of the pagevar _pushState = history.pushState;
history.pushState =function(state, title, url){
_pushState.call(this, state, title, url);
window.dispatchEvent(newCustomEvent('state-changed',{detail: state}));};// repeat the above for replaceState too}+')(); this.remove();';// remove the DOM script element// And here content script listens to our DOM script custom events
window.addEventListener('state-changed',function(e){
console.log('History state changed', e.detail, location.hash);
doSomething();});
Outra abordagem, dependendo de como você está alterando a div. Se você estiver usando o JQuery para alterar o conteúdo de uma div com seu método html (), poderá estender esse método e chamar uma função de registro sempre que colocar o html em uma div.
(function( $, oldHtmlMethod ){// Override the core html method in the jQuery object.
$.fn.html =function(){// Execute the original HTML method using the// augmented arguments collection.var results = oldHtmlMethod.apply(this, arguments );
com.invisibility.elements.findAndRegisterElements(this);return results;};})( jQuery, jQuery.fn.html );
Nós apenas interceptamos as chamadas para html (), chamamos uma função de registro com isso, que no contexto se refere ao elemento de destino obtendo novo conteúdo, depois passamos a chamada para a função original jquery.html (). Lembre-se de retornar os resultados do método html () original, porque o JQuery espera isso para o encadeamento de métodos.
Além das ferramentas "brutas" fornecidas pela MutationObserverAPI , existem bibliotecas de "conveniência" para trabalhar com mutações do DOM.
Considere: MutationObserver representa cada alteração do DOM em termos de subárvores. Portanto, se você está, por exemplo, esperando que um determinado elemento seja inserido, ele pode estar dentro dos filhos de mutations.mutation[i].addedNodes[j].
Outro problema é quando seu próprio código, em reação a mutações, altera o DOM - você geralmente deseja filtrá-lo.
Uma boa biblioteca de conveniência que resolve esses problemas é mutation-summary(exoneração de responsabilidade: não sou o autor, apenas um usuário satisfeito), que permite especificar consultas sobre o que lhe interessa e obter exatamente isso.
([{}])
logon no console, que mostra o esperadoMutationRecord
quando clico nele. Verifique novamente, pois pode ter sido uma falha técnica temporária no JSFiddle. Ainda não testei no IE, pois não tenho o IE 10, que atualmente é a única versão para suportar eventos de mutação.Editar
Esta resposta está agora obsoleta. Veja a resposta dos apsillers .
Como se trata de uma extensão do Chrome, você também pode usar o evento DOM padrão -
DOMSubtreeModified
. Veja o suporte para este evento nos navegadores. É suportado no Chrome desde 1.0.Veja um exemplo de trabalho aqui .
fonte
Muitos sites usam o AJAX para adicionar / mostrar / alterar conteúdo dinamicamente. Às vezes, é usado em vez da navegação no site; portanto, o URL atual é alterado de forma programática e, nesse caso, os scripts de conteúdo não são executados automaticamente pelo navegador, pois a página não é obtida totalmente do servidor remoto.
Métodos JS comuns para detectar alterações de página disponíveis em um script de conteúdo .
MutationObserver ( docs ) para detectar literalmente alterações no DOM:
Ouvinte de evento para sites que sinalizam alteração de conteúdo enviando um evento DOM:
pjax:end
nodocument
usado por muitos sites baseados em pjax por exemplo GitHub,consulte Como executar jQuery antes e depois de uma carga pjax?
message
nowindow
usado por exemplo pesquisa do Google no navegador Chrome,veja extensão do Chrome detectar Google atualização pesquisa
spfdone
nodocument
usado por Youtube,veja Como detectar navegação de página no Youtube e Modificar HTML antes de página é processada?
Verificação periódica do DOM via setInterval :
Obviamente, isso funcionará apenas nos casos em que você esperar que um elemento específico identificado por seu ID / seletor apareça e não permitirá que você detecte universalmente novo conteúdo adicionado dinamicamente, a menos que invente algum tipo de impressão digital o conteúdo existente.
API de histórico de cloaking dentro de um script DOM injetado :
Ouvindo hashchange , popstate eventos:
Específico para extensões: detecte alterações de URL em uma página de segundo plano / evento .
Há uma API avançada para trabalhar com a navegação: webNavigation , webRequest , mas usaremos o chrome.tabs.onUpdated listener de evento simples que envia uma mensagem para o script de conteúdo:
manifest.json:
declarar página de segundo plano / evento
declarar permissão de inclusão de script de conteúdo .
"tabs"
background.js
content.js
fonte
Outra abordagem, dependendo de como você está alterando a div. Se você estiver usando o JQuery para alterar o conteúdo de uma div com seu método html (), poderá estender esse método e chamar uma função de registro sempre que colocar o html em uma div.
Nós apenas interceptamos as chamadas para html (), chamamos uma função de registro com isso, que no contexto se refere ao elemento de destino obtendo novo conteúdo, depois passamos a chamada para a função original jquery.html (). Lembre-se de retornar os resultados do método html () original, porque o JQuery espera isso para o encadeamento de métodos.
Para obter mais informações sobre substituição e extensão de método, consulte http://www.bennadel.com/blog/2009-Using-Self-Executing-Function-Arguments-To-Override-Core-jQuery-Methods.htm , que é onde Eu usei a função de fechamento. Verifique também o tutorial de plugins no site do JQuery.
fonte
Além das ferramentas "brutas" fornecidas pela
MutationObserver
API , existem bibliotecas de "conveniência" para trabalhar com mutações do DOM.Considere: MutationObserver representa cada alteração do DOM em termos de subárvores. Portanto, se você está, por exemplo, esperando que um determinado elemento seja inserido, ele pode estar dentro dos filhos de
mutations.mutation[i].addedNodes[j]
.Outro problema é quando seu próprio código, em reação a mutações, altera o DOM - você geralmente deseja filtrá-lo.
Uma boa biblioteca de conveniência que resolve esses problemas é
mutation-summary
(exoneração de responsabilidade: não sou o autor, apenas um usuário satisfeito), que permite especificar consultas sobre o que lhe interessa e obter exatamente isso.Exemplo de uso básico dos documentos:
fonte