jQuery(event): watch element style

你。 提交于 2019-11-30 09:47:56
Jacob Relkin

As far as I know, the only way to do this would be with a timer.

I created a small jQuery plugin (yes, right here, right now) that does this against a jQuery set:

EDIT this plugin is now on GitHub: https://github.com/jacobrelkin/jquery-watcher

$.fn.watch = function(property, callback) {
   return $(this).each(function() {
       var self = this;
       var old_property_val = this[property];
       var timer;

       function watch() {
          if($(self).data(property + '-watch-abort') == true) {
             timer = clearInterval(timer);
             $(self).data(property + '-watch-abort', null);
             return;
          }

          if(self[property] != old_property_val) {
             old_property_val = self[property];
             callback.call(self);
          }
       }
       timer = setInterval(watch, 700);
   });
};

$.fn.unwatch = function(property) {
   return $(this).each(function() {
       $(this).data(property + '-watch-abort', true);
   });
};

Usage:

$('.watch-me').watch('style', function() {
   //"this" in this scope will reference the object on which the property changed
   if($(this).css('display') == 'block') { 
       //do something...
   }
});

To clear this property watcher:

$('.watch-me').unwatch('style');
Amjad Masad

You may use object.watch function however its non standard, there is already a cross-browser implementation Object.watch() for all browsers?

$('.watch-me').get(0).watch('style', handlerFunction);
function startPolling()
{
    var handle = window.setInterval(function(){

        var element = $(".watch-me");
        if (element.css("display") == "block") {
            // trigger the event
            window.clearInterval(handle);
        }

    }, 100);
}

When you want to start watching simply write:

startPolling();

I wrote a jQuery plugin for watching changes on DOM element properties/attributes and CSS properties that some might find more intuitive/easier to use: jQuery.watch

In order to accomplish what you're after you would do something like this:

$('.watch-me').watch({
    'display': function( oldVal, newVal, elm ) {
        if (newVal == 'block') {
            // Do something
        }
    }
});

The plugin also supports tracking the return values of jQuery methods on watched elements, so you could for instance fire a callback when the return value of a jQuery method changes when called on a given element.

Since you can't rely on the DOM Mutation Events due to no support for IE before 9, I think you'll be required to set a polling timer to watch. For example:

var watched = $('.watch-me');
var lastDisplay = watched.css('display');

// Peek at the property about twice per second
setInterval(function(){
  var curDisplay = watched.css('display');
  if (curDisplay!=lastDisplay){
    // Do what you want here.
    lastDisplay = curDisplay;
  }
},500);

If you want to cancel the watching after it changes once:

var watched = $('.watch-me');
var lastDisplay = watched.css('display');
var timer = setInterval(function(){
  if (watched.css('display')!=lastDisplay){
    // Do what you want here.
    clearInterval( timer );
  }
},500);

This is highly experimental (you have been warned!) and might not be a good fit to your problem or answer to this question, but it has occurred to me that you can do two things:

1 - Override the jQuery's core .toggle method to add some data to the elements it gets applied to.

2 - Bind a changeData event handler to elements, as of jQuery 1.4.4

What that means is, you can make something happen whenever an element gets toggled. The same principle could apply to the .hide and .show methods, or any other methods for that matter.

// 1 - override .toggle()
var original = jQuery.fn.toggle;
jQuery.fn.toggle = function() {
    console.log("Override method: toggle()");

    // call the original toggle
    original.apply(this, arguments);

    // record the element's visibility
    $(this).data("visible", $(this).is(":visible"));

    return this;
};

// 2 - bind a changeData event handler to a 'watch list'
$('div').bind("changeData", function() {
    alert("Visibility changed to: " + $.data(this, 'visible'));
});

<!-- exhaustive test markup -->
<div id="test">Hello</div>
<div id="test2" style="display:none">Hello 2</div>

// go!
$(document).ready(function() {
    $("#test").toggle();
    $("#test2").toggle();
});

Try it out here: http://jsfiddle.net/karim79/nreqv/1/

This might be considered not answering the question, but it would be better to use JQuery custom events and the .trigger method than using intervals and watching (which just consumes resources).

More to the point, elements can subscribe to new triggered events from objects that they are "watch"ing.

Take a look here:

http://www.sitepoint.com/jquery-custom-events/

check https://developer.mozilla.org/en/docs/Web/API/MutationObserver

var target = _DOM_;
var lastDisplayStyle = _DOM_.style.display;
var observer = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
        if (mutation.type === "attributes") {
            if (lastDisplayStyle !== _DOM_.style.display){
               // your code there
            }
        }
    });
});

var config = { attributes: true };
observer.observe(target, config);

P.S. watch / unwatch are deprecated. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/watch Do not use setInterval solutions!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!