簡體   English   中英

檢測元素是否已通過javascript調整大小?

[英]Detect if an element has been resized via javascript?

是否可以僅將事件偵聽器添加到某些元素以檢測其高度或寬度是否已被修改? 我想不使用密集的方法來這樣做:

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

理想情況下,我想綁定到特定元素:

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

似乎在窗口上使用調整大小處理程序是唯一的解決方案,但這感覺有點過頭了。 它還不考慮以編程方式修改元素尺寸的情況。

我只是想出一種純粹基於事件的方法來檢測任何可能包含子元素的元素的大小調整,因此我粘貼了以下解決方案中的代碼。

另請參閱原始博客文章 ,其中包含一些歷史細節。 此答案的先前版本基於博客文章的先前版本。


以下是啟用調整大小事件監聽所需的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

這是一個帶有watchunwatch方法的jQuery插件 ,可以監視元素的特定屬性。 它作為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()的間隔(以毫秒為單位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;
}

對的,這是可能的。 您將必須跟蹤加載的所有元素並將其存儲。 您可以在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/http://jsfiddle.net/DerekL/6Evk6/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM