Можно ли прослушать событие "изменение стиля"?

Можно ли создать прослушиватель событий в jQuery, который может быть привязан к любым изменениям стиля? Например, если я хочу "сделать" что-то, когда элемент изменяет размеры или любые другие изменения в атрибуте стиля, которые я мог бы сделать:

$('div').bind('style', function() {
    console.log($(this).css('height'));
});

$('div').height(100); // yields '100'

Было бы очень полезно.

Любые идеи?

UPDATE

Извините за ответ на это сам, но я написал аккуратное решение, которое может поместиться кому-то другому:

(function() {
    var ev = new $.Event('style'),
        orig = $.fn.css;
    $.fn.css = function() {
        $(this).trigger(ev);
        return orig.apply(this, arguments);
    }
})();

Это временно переопределит внутренний метод prototype.css и переопределит его с помощью триггера в конце. Поэтому он работает следующим образом:

$('p').bind('style', function(e) {
    console.log( $(this).attr('style') );
});

$('p').width(100);
$('p').css('color','red');

Ответ 1

Так как jQuery является открытым исходным кодом, я бы предположил, что вы можете настроить функцию css для вызова функции по вашему выбору при каждом ее вызове (передача объекта jQuery). Конечно, вы захотите прочесывать код jQuery, чтобы убедиться, что нет ничего другого, что он использует для внутренних свойств CSS. В идеале вам нужно написать отдельный плагин для jQuery, чтобы он не мешал самой библиотеке jQuery, но вам придется решить, возможно ли это для вашего проекта.

Ответ 2

Вещи немного изменились с тех пор, как был задан вопрос - теперь можно использовать MutationObserver для обнаружения изменений в атрибуте 'style' элемент, не требуется jQuery:

var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutationRecord) {
        console.log('style changed!');
    });    
});

var target = document.getElementById('myId');
observer.observe(target, { attributes : true, attributeFilter : ['style'] });

Аргумент, который передается функции обратного вызова, представляет собой объект MutationRecord, который позволяет получить старые и новые значения стиля.

Поддержка хороша в современных браузерах, включая IE 11 +.

Ответ 3

Объявление вашего объекта события должно быть внутри вашей новой функции css. В противном случае событие может быть запущено только один раз.

(function() {
    orig = $.fn.css;
    $.fn.css = function() {
        var ev = new $.Event('style');
        orig.apply(this, arguments);
        $(this).trigger(ev);
    }
})();

Ответ 4

Я думаю, лучший ответ, если от Майка в случае, если вы не можете запустить свое мероприятие, потому что оно не из вашего кода. Но я получаю некоторые ошибки, когда использовал их. Поэтому я пишу новый ответ, чтобы показать вам код, который я использую.

Удлинитель

// Extends functionality of ".css()"
// This could be renamed if you'd like (i.e. "$.fn.cssWithListener = func ...")
(function() {
    orig = $.fn.css;
    $.fn.css = function() {
        var result = orig.apply(this, arguments);
        $(this).trigger('stylechanged');
        return result;
    }
})();

Использование

// Add listener
$('element').on('stylechanged', function () {
    console.log('css changed');
});

// Perform change
$('element').css('background', 'red');

Я получил ошибку, потому что var ev = new $.Event('style'); Что-то вроде стиля не было определено в HtmlDiv.. Я удалил его, и теперь я запускаю $(this).trigger( "stylechanged" ). Другая проблема заключалась в том, что Майк не возвращал результат $(css,..), тогда он может создавать проблемы в некоторых случаях. Поэтому я получаю результат и возвращаю его. Теперь работает ^^ В каждом изменении css включаются некоторые библиотеки, которые я не могу изменить и вызвать событие.

Ответ 5

Как утверждали другие, если у вас есть контроль над тем, какой код меняет стиль элемента, вы можете запустить настраиваемое событие при изменении высоты элемента:

$('#blah').bind('height-changed',function(){...});
...
$('#blah').css({height:'100px'});
$('#blah').trigger('height-changed');

В противном случае, хотя довольно ресурсоемкий, вы можете установить таймер для периодической проверки изменений высоты элемента...

Ответ 6

Нет встроенной поддержки события изменения стиля в jQuery или в java script. Но jQuery поддерживает создание пользовательского события и прослушивает его, но каждый раз, когда происходит изменение, у вас должен быть способ запускать его самостоятельно. Таким образом, это не будет полным решением.

Ответ 7

Интересный вопрос. Проблема в том, что height() не принимает обратный вызов, поэтому вы не сможете запустить обратный вызов. Используйте либо animate(), либо css(), чтобы установить высоту, а затем вызвать пользовательское событие в обратном вызове. Вот пример использования анимации(), тестирования и работы (demo), как доказательство концепции:

$('#test').bind('style', function() {
    alert($(this).css('height'));
});

$('#test').animate({height: 100},function(){
$(this).trigger('style');
}); 

Ответ 8

Просто добавление и формализация решения @David сверху:

Обратите внимание, что функции jQuery являются цепями и возвращают 'this', так что несколько вызовов могут вызываться один за другим (например, $container.css("overflow", "hidden").css("outline", 0);).

Таким образом, улучшенный код должен быть:

(function() {
    var ev = new $.Event('style'),
        orig = $.fn.css;
    $.fn.css = function() {
        var ret = orig.apply(this, arguments);
        $(this).trigger(ev);
        return ret; // must include this
    }
})();

Ответ 9

У меня была такая же проблема, поэтому я написал это. Он работает довольно хорошо. Выглядит отлично, если вы смешиваете его с некоторыми переходами CSS.

function toggle_visibility(id) {
   var e = document.getElementById("mjwelcome");
   if(e.style.height == '')
      e.style.height = '0px';
   else
      e.style.height = '';
}

Ответ 10

вы можете попробовать JQuery плагин, он запускает события, когда css изменяется и его легко использовать

http://meetselva.github.io/#gist-section-attrchangeExtension
 $([selector]).attrchange({
  trackValues: true, 
  callback: function (e) {
    //console.log( '<p>Attribute <b>' + e.attributeName +'</b> changed from <b>' + e.oldValue +'</b> to <b>' + e.newValue +'</b></p>');
    //event.attributeName - Attribute Name
    //event.oldValue - Prev Value
    //event.newValue - New Value
  }
});

Ответ 11

Вы также можете использовать точку прерывания Chrome (я использовал версию 60.0.3112.113 (Official Build) (64-разрядная версия)) - см. этот снимок экрана: Chrome Breakpoint