检测元素是否已通过javascript调整大小?

时间:2012-02-13 03:20:43

标签: javascript html css

是否可以简单地将事件侦听器添加到某些元素以检测其高度或宽度是否已被修改?我喜欢这样做而不使用强化的东西:

$(window).resize(function() { ... });

理想情况下,我想绑定特定元素:

$("#primaryContent p").resize(function() { ... });

似乎在窗口上使用调整大小处理程序是唯一的解决方案,但这感觉就像是矫枉过正。它也没有考虑以编程方式修改元素尺寸的情况。

3 个答案:

答案 0 :(得分:4)

以下是a jQuery plugin watchunwatch方法,可以查看元素的特定属性。它被调用为jQuery对象的方法。它在浏览器中使用内置功能,在DOM更改时返回事件,并对不支持这些事件的浏览器使用setTimeout()

watch函数的一般语法如下:

$("selector here").watch(props, func, interval, id);
  • props是您希望的以逗号分隔的字符串 观看(例如"width,height")。
  • func是一个回调函数,传递参数watchData, index,其中watchData指的是{ id: itId, props: [], func: func, vals: [] }形式的对象,index是索引改变了的财产。 this指的是已更改的元素。
  • interval是不支持在DOM中观看属性的浏览器中setInterval()的间隔(以毫秒为单位)。
  • id是标识此观察程序的可选ID,用于从jQuery对象中删除特定的观察程序。

unwatch函数的一般语法如下:

$("selector here").unwatch(id);
  • id是一个可选ID,用于标识要删除的观察程序。如果未指定id,则将删除该对象中的所有观察者。

对于那些好奇的人,插件的代码如下:

$.fn.watch = function(props, func, interval, id) {
    /// <summary>
    /// Allows you to monitor changes in a specific
    /// CSS property of an element by polling the value.
    /// when the value changes a function is called.
    /// The function called is called in the context
    /// of the selected element (ie. this)
    /// </summary>    
    /// <param name="prop" type="String">CSS Property to watch. If not specified (null) code is called on interval</param>    
    /// <param name="func" type="Function">
    /// Function called when the value has changed.
    /// </param>    
    /// <param name="func" type="Function">
    /// optional id that identifies this watch instance. Use if
    /// if you have multiple properties you're watching.
    /// </param>
    /// <param name="id" type="String">A unique ID that identifies this watch instance on this element</param>  
    /// <returns type="jQuery" /> 
    if (!interval)
        interval = 200;
    if (!id)
        id = "_watcher";

    return this.each(function() {
        var _t = this;
        var el = $(this);
        var fnc = function() { __watcher.call(_t, id) };
        var itId = null;

        if (typeof (this.onpropertychange) == "object")
            el.bind("propertychange." + id, fnc);
        else if ($.browser.mozilla)
            el.bind("DOMAttrModified." + id, fnc);
        else
            itId = setInterval(fnc, interval);

        var data = { id: itId,
            props: props.split(","),
            func: func,
            vals: []
        };
        $.each(data.props, function(i) { data.vals[i] = el.css(data.props[i]); });
        el.data(id, data);
    });

    function __watcher(id) {
        var el = $(this);
        var w = el.data(id);

        var changed = false;
        var i = 0;
        for (i; i < w.props.length; i++) {
            var newVal = el.css(w.props[i]);
            if (w.vals[i] != newVal) {
                w.vals[i] = newVal;
                changed = true;
                break;
            }
        }
        if (changed && w.func) {
            var _t = this;
            w.func.call(_t, w, i)
        }
    }
}
$.fn.unwatch = function(id) {
    this.each(function() {
        var w = $(this).data(id);
        var el = $(this);
        el.removeData();

        if (typeof (this.onpropertychange) == "object")
            el.unbind("propertychange." + id, fnc);
        else if ($.browser.mozilla)
            el.unbind("DOMAttrModified." + id, fnc);
        else
            clearInterval(w.id);
    });
    return this;
}

答案 1 :(得分:4)

我想出了一个纯粹的基于事件的方法来检测任何可以包含子元素的元素的元素大小调整,我已经粘贴了下面解决方案中的代码。

另请参阅original blog post,其中包含一些历史详细信息。此答案的先前版本基于博客文章的先前版本。


以下是启用调整大小事件监听所需的JavaScript。

(function(){
  var attachEvent = document.attachEvent;
  var isIE = navigator.userAgent.match(/Trident/);
  var requestFrame = (function(){
    var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
        function(fn){ return window.setTimeout(fn, 20); };
    return function(fn){ return raf(fn); };
  })();

  var cancelFrame = (function(){
    var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
           window.clearTimeout;
    return function(id){ return cancel(id); };
  })();

  function resizeListener(e){
    var win = e.target || e.srcElement;
    if (win.__resizeRAF__) cancelFrame(win.__resizeRAF__);
    win.__resizeRAF__ = requestFrame(function(){
      var trigger = win.__resizeTrigger__;
      trigger.__resizeListeners__.forEach(function(fn){
        fn.call(trigger, e);
      });
    });
  }

  function objectLoad(e){
    this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__;
    this.contentDocument.defaultView.addEventListener('resize', resizeListener);
  }

  window.addResizeListener = function(element, fn){
    if (!element.__resizeListeners__) {
      element.__resizeListeners__ = [];
      if (attachEvent) {
        element.__resizeTrigger__ = element;
        element.attachEvent('onresize', resizeListener);
      }
      else {
        if (getComputedStyle(element).position == 'static') element.style.position = 'relative';
        var obj = element.__resizeTrigger__ = document.createElement('object'); 
        obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;');
        obj.__resizeElement__ = element;
        obj.onload = objectLoad;
        obj.type = 'text/html';
        if (isIE) element.appendChild(obj);
        obj.data = 'about:blank';
        if (!isIE) element.appendChild(obj);
      }
    }
    element.__resizeListeners__.push(fn);
  };

  window.removeResizeListener = function(element, fn){
    element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
    if (!element.__resizeListeners__.length) {
      if (attachEvent) element.detachEvent('onresize', resizeListener);
      else {
        element.__resizeTrigger__.contentDocument.defaultView.removeEventListener('resize', resizeListener);
        element.__resizeTrigger__ = !element.removeChild(element.__resizeTrigger__);
      }
    }
  }
})();

用法

以下是此解决方案的伪代码用法:

var myElement = document.getElementById('my_element'),
    myResizeFn = function(){
        /* do something on resize */
    };
addResizeListener(myElement, myResizeFn);
removeResizeListener(myElement, myResizeFn);

演示

http://www.backalleycoder.com/resize-demo.html

答案 2 :(得分:0)

是的,这是可能的。您必须在加载时跟踪所有元素并存储它。您可以试用演示here。在其中,您不必使用任何库,但我使用jQuery只是为了更快。

第一件事 - 存储他们的初始尺寸

您可以使用此方法执行此操作:

var state = [];           //Create an public (not necessary) array to store sizes.

$(window).load(function() {
    $("*").each(function() {
        var arr = [];
        arr[0] = this
        arr[1] = this.offsetWidth;
        arr[2] = this.offsetHeight;

        state[state.length] = arr;    //Store all elements' initial size
    });
});

同样,我使用jQuery只是为了快。

第二 - 检查!

当然,您需要检查是否已更改:

function checksize(ele) {
    for (var i = 0; i < state.length; i++) {       //Search through your "database"
        if (state[i][0] == ele) {
            if (state[i][1] == ele.offsetWidth && state[i][2] == ele.offsetHeight) {
                return false
            } else {
                return true
            }
        }
    }
}

如果它没有被更改,它将返回false,如果它已被更改,则返回true

希望这会帮助你!

演示:http://jsfiddle.net/DerekL/6Evk6/