首页 文章

如何检测DIV的尺寸变化?

提问于
浏览
261

我有以下示例html,有一个DIV,宽度为100% . 它包含一些元素 . 在执行窗口重新调整大小时,可以重新定位内部元素,并且div的尺寸可以改变 . 我问是否有可能挂钩div的尺寸变化事件?以及如何做到这一点?我目前将回调函数绑定到目标DIV上的jQuery resize事件,但是,没有输出控制台日志,请参见下文:

Before Resize

enter image description here

<html>
<head>
    <script type="text/javascript" language="javascript" src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
    <script type="text/javascript" language="javascript">
            $('#test_div').bind('resize', function(){
                console.log('resized');
            });
    </script>
</head>
<body>
    <div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" />
        <input type="button" value="button 2" />
        <input type="button" value="button 3" />
    </div>
</body>
</html>

21 回答

  • -1

    有一种非常有效的方法可以确定元素的大小是否已更改 .

    http://marcj.github.io/css-element-queries/

    该库有一个 ResizeSensor 类,可用于调整大小 .
    它使用基于事件的方法,因此它会浪费CPU时间 .

    例:

    new ResizeSensor(jQuery('#divId'), function(){ 
        console.log('content dimension changed');
    });
    

    请不要使用jQuery onresize插件,因为它使用 setTimeout() 循环来检查更改 .
    THIS IS INCREDIBLY SLOW AND NOT ACCURATE .

    披露:我直接与此库相关联 .

  • 14

    一个新标准是Resize Observer api,可在Chrome 64中使用 .

    function outputsize() {
     width.value = textbox.offsetWidth
     height.value = textbox.offsetHeight
    }
    outputsize()
    
    new ResizeObserver(outputsize).observe(textbox)
    
    Width: <output id="width">0</output><br>
    Height: <output id="height">0</output><br>
    <textarea id="textbox">Resize me</textarea><br>
    

    调整观察者大小

    规格:https://wicg.github.io/ResizeObserver

    Polyfills:https://github.com/WICG/ResizeObserver/issues/3

    Firefox问题:https://bugzil.la/1272409

    Safari问题:http://wkb.ug/157743

    目前的支持:http://caniuse.com/#feat=resizeobserver

  • -1

    您必须在 window 对象上绑定 resize 事件,而不是在通用html元素上绑定 .

    然后你可以使用这个:

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

    在回调函数中,您可以检查 div 调用的新宽度

    $('.a-selector').width();
    

    所以,你的问题的答案是 no ,你不能将 resize 事件绑定到div .

  • 7

    从长远来看,您将能够使用ResizeObserver .

    new ResizeObserver(callback).observe(element);
    

    不幸的是,许多浏览器目前默认不支持它 .

    同时,您可以使用如下功能 . 因为,大多数元素大小的更改将来自窗口大小调整或来自DOM中的更改 . 您可以使用窗口的resize事件监听窗口大小调整,并且可以使用MutationObserver监听DOM更改 .

    下面是一个函数的示例,当提供的元素的大小因这些事件中的任何一个而发生更改时,它将回调您:

    var onResize = function(element, callback) {
      if (!onResize.watchedElementData) {
        // First time we are called, create a list of watched elements
        // and hook up the event listeners.
        onResize.watchedElementData = [];
    
        var checkForChanges = function() {
          onResize.watchedElementData.forEach(function(data) {
            if (data.element.offsetWidth !== data.offsetWidth ||
                data.element.offsetHeight !== data.offsetHeight) {
              data.offsetWidth = data.element.offsetWidth;
              data.offsetHeight = data.element.offsetHeight;
              data.callback();
            }
          });
        };
    
        // Listen to the window's size changes
        window.addEventListener('resize', checkForChanges);
    
        // Listen to changes on the elements in the page that affect layout 
        var observer = new MutationObserver(checkForChanges);
        observer.observe(document.body, { 
          attributes: true,
          childList: true,
          characterData: true,
          subtree: true 
        });
      }
    
      // Save the element we are watching
      onResize.watchedElementData.push({
        element: element,
        offsetWidth: element.offsetWidth,
        offsetHeight: element.offsetHeight,
        callback: callback
      });
    };
    
  • 7

    看看这个http://benalman.com/code/projects/jquery-resize/examples/resize/

    它有各种例子 . 尝试调整窗口大小,看看容器元素中的元素是如何调整的 .

    Example with js fiddle to explain how to get it work.
    看看这个小提琴http://jsfiddle.net/sgsqJ/4/

    因为resize()事件绑定到具有类“test”的元素以及窗口对象和窗口对象$(' . test')的resize回调中 . 调用resize() .

    例如

    $('#test_div').bind('resize', function(){
                console.log('resized');
    });
    
    $(window).resize(function(){
       $('#test_div').resize();
    });
    
  • 3

    最好的解决方案是使用所谓的 Element Queries . 但是,它们不是标准的,没有规范存在 - 唯一的选择是使用其中一个可用的polyfill /库,如果你想这样做的话 .

    元素查询背后的想法是允许页面上的某个容器响应提供给它的空间 . 这将允许编写一次组件,然后将其放在页面的任何位置,同时将其内容调整为当前大小 . No matter what the Window size is. 这是我们在元素查询和媒体查询之间看到的第一个区别 . 每个人都希望在某些时候创建一个规范来标准化元素查询(或实现相同目标的东西),并使它们本机,干净,简单和健壮 . 大多数人都认为媒体查询非常有限,无法帮助进行模块化设计和真正的响应 .

    有一些polyfill /库以不同的方式解决问题(虽然可以称为解决方法而不是解决方案):

    我已经看到了提出类似问题的其他解决方案 . 通常他们使用计时器或窗口/视口大小,这不是一个真正的解决方案 . 此外,我认为理想情况下这应该主要在CSS中解决,而不是在javascript或html中 .

  • 2

    当MarcJ的解决方案没有找到时,我发现这个库可以工作:

    https://github.com/sdecima/javascript-detect-element-resize

    它非常轻巧,可以通过CSS或简单的HTML加载/渲染来检测自然调整大小 .

    代码示例(取自链接):

    <script type="text/javascript" src="detect-element-resize.js"></script>
    <script type="text/javascript">
      var resizeElement = document.getElementById('resizeElement'),
          resizeCallback = function() {
              /* do something */
          };
      addResizeListener(resizeElement, resizeCallback);
      removeResizeListener(resizeElement, resizeCallback);
    </script>
    
  • 9

    ResizeSensor.js是一个巨大的库,但我把它减少到 THIS .

    泡泡袖:

    function ResizeSensor(element, callback)
    {
        let zIndex = parseInt(getComputedStyle(element));
        if(isNaN(zIndex)) { zIndex = 0; };
        zIndex--;
    
        let expand = document.createElement('div');
        expand.style.position = "absolute";
        expand.style.left = "0px";
        expand.style.top = "0px";
        expand.style.right = "0px";
        expand.style.bottom = "0px";
        expand.style.overflow = "hidden";
        expand.style.zIndex = zIndex;
        expand.style.visibility = "hidden";
    
        let expandChild = document.createElement('div');
        expandChild.style.position = "absolute";
        expandChild.style.left = "0px";
        expandChild.style.top = "0px";
        expandChild.style.width = "10000000px";
        expandChild.style.height = "10000000px";
        expand.appendChild(expandChild);
    
        let shrink = document.createElement('div');
        shrink.style.position = "absolute";
        shrink.style.left = "0px";
        shrink.style.top = "0px";
        shrink.style.right = "0px";
        shrink.style.bottom = "0px";
        shrink.style.overflow = "hidden";
        shrink.style.zIndex = zIndex;
        shrink.style.visibility = "hidden";
    
        let shrinkChild = document.createElement('div');
        shrinkChild.style.position = "absolute";
        shrinkChild.style.left = "0px";
        shrinkChild.style.top = "0px";
        shrinkChild.style.width = "200%";
        shrinkChild.style.height = "200%";
        shrink.appendChild(shrinkChild);
    
        element.appendChild(expand);
        element.appendChild(shrink);
    
        function setScroll()
        {
            expand.scrollLeft = 10000000;
            expand.scrollTop = 10000000;
    
            shrink.scrollLeft = 10000000;
            shrink.scrollTop = 10000000;
        };
        setScroll();
    
        let size = element.getBoundingClientRect();
    
        let currentWidth = size.width;
        let currentHeight = size.height;
    
        let onScroll = function()
        {
            let size = element.getBoundingClientRect();
    
            let newWidth = size.width;
            let newHeight = size.height;
    
            if(newWidth != currentWidth || newHeight != currentHeight)
            {
                currentWidth = newWidth;
                currentHeight = newHeight;
    
                callback();
            }
    
            setScroll();
        };
    
        expand.addEventListener('scroll', onScroll);
        shrink.addEventListener('scroll', onScroll);
    };
    

    如何使用它:

    let container = document.querySelector(".container");
    new ResizeSensor(container, function()
    {
        console.log("dimension changed:", container.clientWidth, container.clientHeight);
    });
    
  • 12

    我不建议使用setTimeout()hack,因为它会降低性能!相反,您可以使用DOM mutation observers来收听Div大小更改 .

    JS:

    var observer = new MutationObserver(function(mutations) {
        console.log('size changed!');
      });
      var target = document.querySelector('.mydiv');
      observer.observe(target, {
        attributes: true
      });
    

    HTML:

    <div class='mydiv'>
    </div>
    

    这是小提琴https://jsfiddle.net/JerryGoyal/uep7nse1/
    尝试更改div大小 .


    您可以在debounce方法中进一步包装您的方法以提高效率 . debounce 将每x毫秒触发您的方法,而不是每毫秒触发DIV正在调整大小 .

  • 110

    只有window对象生成“resize”事件 . 唯一的方法我知道要做你想做的是运行一个定期检查大小的间隔计时器 .

  • 14

    您可以在调整大小时使用 iframeobject 使用 contentWindowcontentDocument . 没有 setIntervalsetTimeout

    步骤:

    • 将元素位置设置为 relative

    • 在透明的绝对隐藏IFRAME中添加

    • 收听 IFRAME.contentWindow - onresize 事件

    HTML的一个例子:

    <div style="height:50px;background-color:red;position:relative;border:1px solid red">
    <iframe style=width:100%;height:100%;position:absolute;border:none;background-color:transparent allowtransparency=true>
    </iframe>
    This is my div
    </div>
    

    The Javascript:

    $('div').width(100).height(100);
    $('div').animate({width:200},2000);
    
    $('object').attr({
        type : 'text/html'
    })
    $('object').on('resize,onresize,load,onload',function(){
        console.log('ooooooooonload')
    })
    
    $($('iframe')[0].contentWindow).on('resize',function(){
        console.log('div changed')
    })
    

    运行示例

    JsFiddle:https://jsfiddle.net/qq8p470d/


    查看更多:

  • 218
    var div = document.getElementById('div');
    div.addEventListener('resize', (event) => console.log(event.detail));
    
    function checkResize (mutations) {
        var el = mutations[0].target;
        var w = el.clientWidth;
        var h = el.clientHeight;
        
        var isChange = mutations
          .map((m) => m.oldValue + '')
          .some((prev) => prev.indexOf('width: ' + w + 'px') == -1 || prev.indexOf('height: ' + h + 'px') == -1);
    
        if (!isChange)
          return;
    
        var event = new CustomEvent('resize', {detail: {width: w, height: h}});
        el.dispatchEvent(event);
    }
    
    var observer = new MutationObserver(checkResize); 
    observer.observe(div, {attributes: true, attributeOldValue: true, attributeFilter: ['style']});
    
    #div {width: 100px; border: 1px solid #bbb; resize: both; overflow: hidden;}
    
    <div id = "div">DIV</div>
    
  • 0

    这篇博文有助于我有效地检测DOM元素的大小变化 .

    http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/

    如何使用此代码...

    AppConfig.addResizeListener(document.getElementById('id'), function () {
      //Your code to execute on resize.
    });
    

    示例使用的打包代码......

    var AppConfig = AppConfig || {};
    AppConfig.ResizeListener = (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);
        }
    
        AppConfig.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);
        };
    
        AppConfig.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__);
                }
            }
        }
    })();
    

    注意:AppConfig是我用于组织可重用函数的命名空间/对象 . 您可以随意搜索并替换您想要的任何名称 .

  • 1

    我的jQuery插件在所有元素上启用"resize"事件而不仅仅是 window .

    https://github.com/dustinpoissant/ResizeTriggering

    $("#myElement") .resizeTriggering().on("resize", function(e){
      // Code to handle resize
    });
    
  • 0

    使用Clay.js(https://github.com/zzarcon/clay),检测元素大小的变化非常简单:

    var el = new Clay('.element');
    
    el.on('resize', function(size) {
        console.log(size.height, size.width);
    });
    
  • 3

    您可以尝试以下代码段中的代码,它使用普通的javascript来满足您的需求 . (运行代码段并单击整页链接以触发警告,如果要测试div,则调整div的大小 . ) .

    基于这个事实,这是一个100毫秒的setInterval,我敢说我的电脑没有发现它太多的CPU饥饿 . (在测试时,Chrome中所有打开的选项卡的总CPU使用了0.1%的CPU . ) . 但是,这只是一个div,如果你想为大量的元素做这个,那么是的,它可能非常渴望CPU . 无论如何,您总是可以使用click事件来停止div调整大小 .

    var width = 0; 
    var interval = setInterval(function(){
    if(width <= 0){
    width = document.getElementById("test_div").clientWidth;
    } 
    if(document.getElementById("test_div").clientWidth!==width) {   
      alert('resized div');
      width = document.getElementById("test_div").clientWidth;
    }    
    
    }, 100);
    
    <div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
            <input type="button" value="button 1" />
            <input type="button" value="button 2" />
            <input type="button" value="button 3" />
    </div>
    

    你也可以查看fiddle

    UPDATE

    var width = 0; 
    function myInterval() {
    var interval = setInterval(function(){
    if(width <= 0){
    width = document.getElementById("test_div").clientWidth;
    } 
    if(document.getElementById("test_div").clientWidth!==width) {   
      alert('resized');
      width = document.getElementById("test_div").clientWidth;
    }    
    
    }, 100);
    return interval;
    }
    var interval = myInterval();
    document.getElementById("clickMe").addEventListener( "click" , function() {
    if(typeof interval!=="undefined") {
    clearInterval(interval);
    alert("stopped div-resize sniffing");
    }
    });
    document.getElementById("clickMeToo").addEventListener( "click" , function() {
    myInterval();
    alert("started div-resize sniffing");
    });
    
    <div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
            <input type="button" value="button 1" id="clickMe" />
            <input type="button" value="button 2" id="clickMeToo" />
            <input type="button" value="button 3" />
    </div>
    

    更新Fiddle

  • 6

    这几乎是最佳答案的精确副本,但它不是链接,而是代码中重要的部分,转换为IMO更易读,更易于理解 . 其他一些小改动包括使用cloneNode(),而不是将html放入js字符串 . 小东西,但你可以按原样复制和粘贴它,它会工作 .

    它的工作方式是让两个不可见的div填充你正在观看的元素,然后在每个元素中放置一个触发器,并设置一个滚动位置,如果大小改变,将导致触发滚动更改 .

    所有真正的功劳都归功于Marc J,但如果你只是在寻找相关的代码,那么它是:

    window.El = {}
    
        El.resizeSensorNode = undefined;
        El.initResizeNode = function() {
            var fillParent = "display: block; position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; z-index: -1; visibility: hidden;";
            var triggerStyle = "position: absolute; left: 0; top: 0; transition: 0s;";
    
            var resizeSensor = El.resizeSensorNode = document.createElement("resizeSensor");
            resizeSensor.style = fillParent;
    
            var expandSensor = document.createElement("div");
            expandSensor.style = fillParent;
            resizeSensor.appendChild(expandSensor);
    
            var trigger = document.createElement("div");
            trigger.style = triggerStyle;
            expandSensor.appendChild(trigger);
    
            var shrinkSensor = expandSensor.cloneNode(true);
            shrinkSensor.firstChild.style = triggerStyle + " width: 200%; height: 200%";
            resizeSensor.appendChild(shrinkSensor);
        }
    
    
        El.onSizeChange = function(domNode, fn) {
            if (!domNode) return;
            if (domNode.resizeListeners) {
                domNode.resizeListeners.push(fn);
                return;
            }
    
            domNode.resizeListeners = [];
            domNode.resizeListeners.push(fn);
    
            if(El.resizeSensorNode == undefined)
                El.initResizeNode();
    
            domNode.resizeSensor = El.resizeSensorNode.cloneNode(true);
            domNode.appendChild(domNode.resizeSensor);
    
            var expand = domNode.resizeSensor.firstChild;
            var expandTrigger = expand.firstChild;
            var shrink = domNode.resizeSensor.childNodes[1];
    
            var reset = function() {
                expandTrigger.style.width = '100000px';
                expandTrigger.style.height = '100000px';
    
                expand.scrollLeft = 100000;
                expand.scrollTop = 100000;
    
                shrink.scrollLeft = 100000;
                shrink.scrollTop = 100000;
            };
    
            reset();
    
            var hasChanged, frameRequest, newWidth, newHeight;
            var lastWidth = domNode.offsetWidth;
            var lastHeight = domNode.offsetHeight;
    
    
            var onResized = function() {
                frameRequest = undefined;
    
                if (!hasChanged) return;
    
                lastWidth = newWidth;
                lastHeight = newHeight;
    
                var listeners = domNode.resizeListeners;
                for(var i = 0; listeners && i < listeners.length; i++) 
                    listeners[i]();
            };
    
            var onScroll = function() {
                newWidth = domNode.offsetWidth;
                newHeight = domNode.offsetHeight;
                hasChanged = newWidth != lastWidth || newHeight != lastHeight;
    
                if (hasChanged && !frameRequest) {
                    frameRequest = requestAnimationFrame(onResized);
                }
    
                reset();
            };
    
    
            expand.addEventListener("scroll", onScroll);
            shrink.addEventListener("scroll", onScroll);
        }
    
  • 14
    jQuery(document).ready( function($) {
    
    function resizeMapDIVs() {
    
    // check the parent value...
    
    var size = $('#map').parent().width();
    
    
    
    if( $size < 640 ) {
    
    //  ...and decrease...
    
    } else {
    
    //  ..or increase  as necessary
    
    }
    
    }
    
    resizeMapDIVs();
    
    $(window).resize(resizeMapDIVs);
    
    });
    
  • 35

    使用 Bharat Patil 回答只需在绑定回调中返回false以防止最大堆栈错误,请参阅下面的示例:

    $('#test_div').bind('resize', function(){
       console.log('resized');
       return false;
    });
    
  • 17

    规范中仅存在 Window.onResize ,但您始终可以使用 IFrame 在DIV中生成新的 Window 对象 .

    请检查answer . 有一个新的小jquery plugin,便携且易于使用 . 您可以随时查看源代码以了解它是如何完成的 .

    <!-- (1) include plugin script in a page -->
    <script src="/src/jquery-element-onresize.js"></script>
    
    // (2) use the detectResizing plugin to monitor changes to the element's size:
    $monitoredElement.detectResizing({ onResize: monitoredElement_onResize });
    
    // (3) write a function to react on changes:
    function monitoredElement_onResize() {    
        // logic here...
    }
    
  • 2

    我认为它无法在高度和宽度上工作 . 只有5行纯javascript(确定它甚至可以更短)http://codepen.io/anon/pen/eNyyVN

    <div id="box" style="
                    height:200px; 
                    width:640px;
                    background-color:#FF0066;
                    resize: both;
                    overflow: auto;" 
                    onclick="myFunction()">
        <p id="sizeTXT" style="
                    font-size: 50px;">
           WxH
        </p>
        </div>
    
    <p>This my example demonstrates how to run a resize check on click for resizable div.</p>
    
    <p>Try to resize the box.</p>
    
    
    <script>
    function myFunction() {
    var boxheight = document.getElementById('box').offsetHeight;
    var boxhwidth = document.getElementById('box').offsetWidth;
    var txt = boxhwidth +"x"+boxheight;
    document.getElementById("sizeTXT").innerHTML = txt;
    }
    </script>
    

相关问题