Como posso disparar um evento se uma classe CSS for adicionada ou alterada usando o jQuery? A alteração de uma classe CSS dispara o change()
evento jQuery ?
Como posso disparar um evento se uma classe CSS for adicionada ou alterada usando o jQuery? A alteração de uma classe CSS dispara o change()
evento jQuery ?
Respostas:
Sempre que você altera uma classe em seu script, você pode usar a trigger
para criar seu próprio evento.
$(this).addClass('someClass');
$(mySelector).trigger('cssClassChanged')
....
$(otherSelector).bind('cssClassChanged', data, function(){ do stuff });
mas, caso contrário, não, não há como preparar um evento quando uma classe muda. change()
somente é acionado após o foco deixar uma entrada cuja entrada foi alterada.
$(function() {
var button = $('.clickme')
, box = $('.box')
;
button.on('click', function() {
box.removeClass('box');
$(document).trigger('buttonClick');
});
$(document).on('buttonClick', function() {
box.text('Clicked!');
});
});
.box { background-color: red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">Hi</div>
<button class="clickme">Click me</button>
changeColor
evento e todos os objetos que assinam esse evento podem reagir de acordo.
IMHO, a melhor solução é combinar duas respostas de @ RamboNo5 e @Jason
Quero dizer, substituindo a função addClass e adicionando um evento personalizado chamado cssClassChanged
// Create a closure
(function(){
// Your base, I'm in it!
var originalAddClassMethod = jQuery.fn.addClass;
jQuery.fn.addClass = function(){
// Execute the original method.
var result = originalAddClassMethod.apply( this, arguments );
// trigger a custom event
jQuery(this).trigger('cssClassChanged');
// return the original result
return result;
}
})();
// document ready function
$(function(){
$("#YourExampleElementID").bind('cssClassChanged', function(){
//do stuff here
});
});
$()
, quando a ação real é iniciada.
cssClassChanged
evento a um elemento, deve estar ciente de que ele será acionado mesmo quando seu filho mudar de classe. Portanto, se, por exemplo, você não desejar acionar esse evento para eles, adicione algo como $("#YourExampleElementID *").on('cssClassChanged', function(e) { e.stopPropagation(); });
após a ligação. Enfim, solução muito boa, obrigado!
Se você deseja detectar alterações de classe, a melhor maneira é usar os Observadores de Mutação, que oferecem controle total sobre qualquer alteração de atributo. No entanto, você mesmo precisa definir o ouvinte e anexá-lo ao elemento que está ouvindo. O bom é que você não precisa acionar nada manualmente depois que o ouvinte é anexado.
$(function() {
(function($) {
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
$.fn.attrchange = function(callback) {
if (MutationObserver) {
var options = {
subtree: false,
attributes: true
};
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(e) {
callback.call(e.target, e.attributeName);
});
});
return this.each(function() {
observer.observe(this, options);
});
}
}
})(jQuery);
//Now you need to append event listener
$('body *').attrchange(function(attrName) {
if(attrName=='class'){
alert('class changed');
}else if(attrName=='id'){
alert('id changed');
}else{
//OTHER ATTR CHANGED
}
});
});
Neste exemplo, o ouvinte de evento é anexado a cada elemento, mas você não deseja isso na maioria dos casos (economize memória). Anexe esse ouvinte "attrchange" ao elemento que você deseja observar.
DOMMutationObserver
.
Eu sugiro que você substitua a função addClass. Você pode fazer assim:
// Create a closure
(function(){
// Your base, I'm in it!
var originalAddClassMethod = jQuery.fn.addClass;
jQuery.fn.addClass = function(){
// Execute the original method.
var result = originalAddClassMethod.apply( this, arguments );
// call your function
// this gets called everytime you use the addClass method
myfunction();
// return the original result
return result;
}
})();
// document ready function
$(function(){
// do stuff
});
Apenas uma prova de conceito:
Veja a essência para ver algumas anotações e manter-se atualizado:
https://gist.github.com/yckart/c893d7db0f49b1ea4dfb
(function ($) {
var methods = ['addClass', 'toggleClass', 'removeClass'];
$.each(methods, function (index, method) {
var originalMethod = $.fn[method];
$.fn[method] = function () {
var oldClass = this[0].className;
var result = originalMethod.apply(this, arguments);
var newClass = this[0].className;
this.trigger(method, [oldClass, newClass]);
return result;
};
});
}(window.jQuery || window.Zepto));
O uso é bastante simples, basta adicionar um novo listender no nó que você deseja observar e manipular as classes normalmente:
var $node = $('div')
// listen to class-manipulation
.on('addClass toggleClass removeClass', function (e, oldClass, newClass) {
console.log('Changed from %s to %s due %s', oldClass, newClass, e.type);
})
// make some changes
.addClass('foo')
.removeClass('foo')
.toggleClass('foo');
this[0]
é indefinido ... simplesmente substituir o final das linhas com var oldClass
e var newClass
com a seguinte atribuição:= (this[0] ? this[0].className : "");
usando a mais recente mutação jquery
var $target = jQuery(".required-entry");
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.attributeName === "class") {
var attributeValue = jQuery(mutation.target).prop(mutation.attributeName);
if (attributeValue.indexOf("search-class") >= 0){
// do what you want
}
}
});
});
observer.observe($target[0], {
attributes: true
});
// qualquer código que atualiza div com a classe required-entry que está em $ target como $ target.addClass ('search-class');
change()
não é acionado quando uma classe CSS é adicionada ou removida ou a definição é alterada. É acionado em circunstâncias como quando um valor da caixa de seleção é selecionado ou desmarcado.
Não tenho certeza se você quer dizer se a definição da classe CSS foi alterada (o que pode ser feito através de programação, mas é tedioso e geralmente não recomendado) ou se uma classe é adicionada ou removida a um elemento. Não há como capturar isso de maneira confiável nos dois casos.
Obviamente, você poderia criar seu próprio evento para isso, mas isso só pode ser descrito como um aviso . Ele não captura o código que não é seu.
Como alternativa, você pode substituir / substituir os addClass()
métodos (etc) no jQuery, mas isso não será capturado quando for feito via Javascript de baunilha (embora eu ache que você também possa substituir esses métodos).
Há mais uma maneira sem acionar um evento personalizado
Um plug-in jQuery para monitorar alterações de CSS de elemento HTML por Rick Strahl
Citando acima
O plug-in de inspeção funciona conectando DOMAttrModified no FireFox, onPropertyChanged no Internet Explorer ou usando um timer com setInterval para lidar com a detecção de alterações em outros navegadores. Infelizmente, o WebKit não suporta DOMAttrModified de forma consistente no momento, portanto, o Safari e o Chrome atualmente precisam usar o mecanismo setInterval, mais lento.
Boa pergunta. Estou usando o menu suspenso Bootstrap e precisava executar um evento quando um menu suspenso do Bootstrap estava oculto. Quando o menu suspenso é aberto, a div que contém o nome de uma classe de "grupo de botões" adiciona uma classe de "aberto"; e o botão em si possui um atributo "ária-expandido" definido como true. Quando o menu suspenso é fechado, essa classe de "aberto" é removida da div que contém e a ária-expandida é alterada de verdadeiro para falso.
Isso me levou a essa pergunta, de como detectar a mudança de classe.
Com o Bootstrap, há "Eventos suspensos" que podem ser detectados. Procure por "Eventos suspensos" neste link. http://www.w3schools.com/bootstrap/bootstrap_ref_js_dropdown.asp
Aqui está um exemplo rápido e sujo de usar esse evento em um menu suspenso de inicialização.
$(document).on('hidden.bs.dropdown', function(event) {
console.log('closed');
});
Agora percebo que isso é mais específico do que a pergunta geral que está sendo feita. Mas imagino que outros desenvolvedores que tentam detectar um evento aberto ou fechado com um menu suspenso do Bootstrap achem isso útil. Como eu, eles podem inicialmente seguir o caminho de simplesmente tentar detectar uma alteração de classe de elemento (o que aparentemente não é tão simples). Obrigado.
Se você precisar disparar um evento específico, poderá substituir o método addClass () para disparar um evento personalizado chamado 'classadded'.
Aqui como:
(function() {
var ev = new $.Event('classadded'),
orig = $.fn.addClass;
$.fn.addClass = function() {
$(this).trigger(ev, arguments);
return orig.apply(this, arguments);
}
})();
$('#myElement').on('classadded', function(ev, newClasses) {
console.log(newClasses + ' added!');
console.log(this);
// Do stuff
// ...
});
Você pode vincular o evento DOMSubtreeModified. Eu adiciono um exemplo aqui:
HTML
<div id="mutable" style="width:50px;height:50px;">sjdfhksfh<div>
<div>
<button id="changeClass">Change Class</button>
</div>
Javascript
$(document).ready(function() {
$('#changeClass').click(function() {
$('#mutable').addClass("red");
});
$('#mutable').bind('DOMSubtreeModified', function(e) {
alert('class changed');
});
});
se você conhece um evento que mudou a classe em primeiro lugar, pode usar um pequeno atraso no mesmo evento e verificar a classe. exemplo
//this is not the code you control
$('input').on('blur', function(){
$(this).addClass('error');
$(this).before("<div class='someClass'>Warning Error</div>");
});
//this is your code
$('input').on('blur', function(){
var el= $(this);
setTimeout(function(){
if ($(el).hasClass('error')){
$(el).removeClass('error');
$(el).prev('.someClass').hide();
}
},1000);
});
var timeout_check_change_class;
function check_change_class( selector )
{
$(selector).each(function(index, el) {
var data_old_class = $(el).attr('data-old-class');
if (typeof data_old_class !== typeof undefined && data_old_class !== false)
{
if( data_old_class != $(el).attr('class') )
{
$(el).trigger('change_class');
}
}
$(el).attr('data-old-class', $(el).attr('class') );
});
clearTimeout( timeout_check_change_class );
timeout_check_change_class = setTimeout(check_change_class, 10, selector);
}
check_change_class( '.breakpoint' );
$('.breakpoint').on('change_class', function(event) {
console.log('haschange');
});