【问题标题】:Is it possible to listen to a "style change" event?是否可以收听“风格改变”事件?
【发布时间】:2011-01-10 14:33:39
【问题描述】:

是否可以在 jQuery 中创建一个可以绑定到任何样式更改的事件侦听器?例如,如果我想在元素更改尺寸或样式属性中的任何其他更改时“做”某事,我可以这样做:

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

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

真的很有用。

有什么想法吗?

更新

很抱歉我自己回答了这个问题,但我写了一个可能适合其他人的简洁解决方案:

(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');

【问题讨论】:

  • 是的,不错的解决方案,但在实际应用程序中,我怀疑这可能会占用大量资源,甚至会使浏览器看起来跟不上用户的交互速度。我很想知道是不是这样。
  • @pixeline:我看不出它应该慢得多。无论如何,jQuery 仍然调用 css 原型,我只是向它添加了一个触发器。所以它基本上只是一个额外的方法调用。
  • 我明白:似乎在用户与应用程序交互的流程中,css() 被调用了很多时间。根据您对该触发器的操作(如果它只是一个控制台日志,我想您当然是安全的),这可能会产生问题。我是在想。这也取决于应用程序。我个人倾向于在我的东西中做很多视觉反馈。
  • 要使其与现有的 jquery css 调用一起工作,还需要做更多的事情:1)您希望从新的 css 函数中返回元素,否则它将破坏流畅的样式 css 调用。例如。 $('p').css('display', 'block').css('color','black');等 2)如果它是对属性值的调用(例如,'obj.css('height');')你会想要返回原始函数的返回值 - 我通过检查参数列表来做到这一点因为该函数只包含一个参数。
  • 我为这种方法制作了一个更强大的版本,当 style 属性本身 被删除时也可以使用。它将为以这种方式删除的每种样式抛出一个“样式”事件。 gist.github.com/bbottema/426810c21ae6174148d4

标签: javascript jquery


【解决方案1】:

自从提出问题以来,事情发生了一些变化——现在可以使用MutationObserver 来检测元素的“样式”属性的变化,不需要 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 对象,它可以让您掌握新旧样式值。

支持是good in modern browsers,包括 IE 11+。

【讨论】:

  • 请记住,这仅适用于内联样式,不适用于样式因类更改或@media 更改而发生更改时。
  • @bfred.it 你知道如何做到这一点吗?在将类的 css 规则应用于元素后,我想运行一些 js。
  • 您可以将getComputedStylesetInterval 一起使用,但这会大大降低您的网站速度。
  • 注意:MutationObserver 并非在所有版本的 Android 4.4 中都有效,尽管 caniuse 这么说。
  • 当文本区域的宽度被拉伸超过 300 像素时,请参阅这个旋转以将文本区域的背景颜色更改为蓝色的示例。 jsfiddle.net/RyanNerd/y2q8wuf0(不幸的是,FF 中似乎有一个错误将脚本挂在 HTMLElement.style.prop = "value"
【解决方案2】:

由于 jQuery 是开源的,我猜您可以调整 css 函数,以便在每次调用时调用您选择的函数(传递 jQuery 对象)。当然,您需要搜索 jQuery 代码以确保它在内部没有使用其他任何东西来设置 CSS 属性。理想情况下,您希望为 jQuery 编写一个单独的插件,这样它就不会干扰 jQuery 库本身,但您必须决定这对您的项目是否可行。

【讨论】:

【解决方案3】:

事件对象的声明必须在新的 css 函数中。否则事件只能触发一次。

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

【讨论】:

  • 太好了,谢谢。有些人告诉更改原始来源,但您的扩展是最好的。我遇到了一些问题,但终于成功了。
  • 在执行完这段代码后,它不断地触发,甚至没有达到要求的结果。
【解决方案4】:

我认为最好的答案是来自 Mike,因为不是来自您的代码,因此您无法启动您的活动。但是我在使用它时遇到了一些错误。因此,我写了一个新答案,向您展示我使用的代码。

扩展

// 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")。另一个问题是 Mike 没有返回 $(css, ..) 的结果,那么它在某些情况下会产生问题。所以我得到结果并返回它。现在可以工作了^^在每个css更改中都包括一些我无法修改和触发事件的库。

【讨论】:

  • 非常有帮助和聪明
  • 就像这个答案中提到的那样,如果事件不是从您的代码生成的,那么一种方法会很有帮助。请注意,这只针对通过 jQuery 中的 css() 函数进行的更改。如果外部代码没有通过 css 函数进行更改,则永远不会调用事件处理程序。
【解决方案5】:

正如其他人所建议的,如果您可以控制更改元素样式的任何代码,则可以在更改元素高度时触发自定义事件:

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

否则,虽然相当耗费资源,但您可以设置一个计时器来定期检查元素高度的变化...

【讨论】:

  • 如果可以访问更改样式的代码,这确实是一个非常简洁的解决方案。
【解决方案6】:

在 jQuery 或 java 脚本中没有对样式更改事件的内置支持。但是jQuery支持创建自定义事件并监听它,但每次有变化时,你应该有办法自己触发它。所以这不是一个完整的解决方案。

【讨论】:

    【解决方案7】:

    你可以试试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
      }
    });
    

    【讨论】:

      【解决方案8】:

      有趣的问题。问题是 height() 不接受回调,因此您将无法启动回调。使用 animate() 或 css() 设置高度,然后在回调中触发自定义事件。这是一个使用 animate() 的示例,经过测试并且可以工作 (demo),作为概念证明:

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

      【讨论】:

      • 抱歉,这证明了什么?您手动trigger() 事件。我认为 OP 在修改样式属性时发生了一些自动触发的事件。
      • @JPot 他表明 height 属性在更改时不会引发事件。
      【解决方案9】:

      只需从上面添加和形式化 @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
          }
      })();
      

      【讨论】:

        【解决方案10】:

        jQuery cssHooks 怎么样?

        也许我不明白这个问题,但是您正在搜索的内容很容易使用cssHooks 完成,而无需更改css() 函数。

        从文档中复制:

        (function( $ ) {
        
        // First, check to see if cssHooks are supported
        if ( !$.cssHooks ) {
          // If not, output an error message
          throw( new Error( "jQuery 1.4.3 or above is required for this plugin to work" ) );
        }
        
        // Wrap in a document ready call, because jQuery writes
        // cssHooks at this time and will blow away your functions
        // if they exist.
        $(function () {
          $.cssHooks[ "someCSSProp" ] = {
            get: function( elem, computed, extra ) {
              // Handle getting the CSS property
            },
            set: function( elem, value ) {
              // Handle setting the CSS value
            }
          };
        });
        
        })( jQuery ); 
        

        https://api.jquery.com/jQuery.cssHooks/

        【讨论】:

          【解决方案11】:

          我有同样的问题,所以我写了这个。它工作得很好。如果您将它与一些 CSS 过渡混合使用,看起来很棒。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-08-06
            • 2018-09-22
            • 2012-01-13
            • 2010-11-12
            • 1970-01-01
            • 2015-09-14
            • 1970-01-01
            相关资源
            最近更新 更多