我有下面的样本html,有一个DIV有100%的宽度。它包含了一些元素。在执行窗口调整大小时,内部元素可能会被重新定位,div的尺寸可能会改变。我在问是否有可能挂钩div的维度变化事件?以及如何做到这一点?我目前绑定回调函数到目标DIV上的jQuery调整大小事件,但是,没有输出控制台日志,如下所示:

<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>

当前回答

纯Javascript解决方案,但只有当元素用css resize按钮调整大小时才能工作:

使用offsetWidth和offsetHeight存储元素大小; 在这个元素上添加一个onclick事件监听器; 当触发时,比较当前的offsetWidth和offsetHeight与存储的值,如果不同,做你想做的,并更新这些值。

其他回答

通过@gman扩展这个答案,这里有一个允许每个元素多次回调的函数,将宽度和高度分解为一个准事件对象。请参阅关于堆栈溢出的嵌入式演示(您可能需要彻底调整主浏览器的大小以触发它)

function elementResizeWatcher(element, callback) { var resolve=function(element) { return (typeof element==='string' ? document[ ['.','#'].indexOf(element.charAt(0)) < 0 ? "getElementById" : "querySelector" ] (element) : element); }, observer, watched = [], checkForElementChanges = function (data) { var w=data.el.offsetWidth,h=data.el.offsetHeight; if ( data.offsetWidth !== w || data.offsetHeight !== h ) { data.offsetWidth = w; data.offsetHeight = h; data.cb({ target : data.el, width : w, height : h }); } }, checkForChanges=function(){ watched.forEach(checkForElementChanges); }, started=false, self = { start: function () { if (!started) { // Listen to the window resize event window.addEventListener("resize", checkForChanges); // Listen to the element being checked for width and height changes observer = new MutationObserver(checkForChanges); observer.observe(document.body, { attributes: true, childList: true, characterData: true, subtree: true }); started=true; } }, stop : function ( ) { if (started) { window.removeEventListener('resize', checkForChanges); observer.disconnect(); started = false; } }, addListener : function (element,callback) { if (typeof callback!=='function') return; var el = resolve(element); if (typeof el==='object') { watched.push({ el : el, offsetWidth : el.offsetWidth, offsetHeight : el.offsetHeight, cb : callback }); } }, removeListener : function (element,callback) { var el = resolve(element); watched = watched.filter(function(data){ return !((data.el===el) && (data.cb===callback)); }); } }; self.addListener(element,callback); self.start(); return self; } var watcher = elementResizeWatcher("#resize_me_on_stack_overflow", function(e){ e.target.innerHTML="i am "+e.width+"px&nbsp;x&nbsp;"+e.height+"px"; }); watcher.addListener(".resize_metoo",function(e) { e.target.innerHTML="and i am "+e.width+"px&nbsp;x&nbsp;"+e.height+"px"; }); var mainsize_info = document.getElementById("mainsize"); watcher.addListener(document.body,function(e) { mainsize_info.innerHTML=e.width+"px&nbsp;x&nbsp;"+e.height+"px"; }); #resize_me_on_stack_overflow{ background-color:lime; } .resize_metoo { background-color:yellow; font-size:36pt; width:50%; } <p> resize the main browser window! <span id="mainsize"><span> </p> <p id="resize_me_on_stack_overflow"> hey, resize me. </p> <p class="resize_metoo"> resize me too. </p>

这几乎是顶部答案的精确副本,但不是链接,它只是重要的代码的一部分,翻译成IMO更易读,更容易理解。其他一些小的改变包括使用cloneNode(),和不把html放入js字符串。很小的东西,但是你可以复制粘贴它就可以了。

它的工作方式是让两个看不见的div填充你正在观看的元素,然后在每个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);
    }

纯香草的实现。

var move = function(e) { if ((e.w && e.w !== e.offsetWidth) || (e.h && e.h !== e.offsetHeight)) { new Function(e.getAttribute('onresize')).call(e); } e.w = e.offsetWidth; e.h = e.offsetHeight; } var resize = function(e) { e.innerText = 'New dimensions: ' + e.w + ',' + e.h; } .resizable { resize: both; overflow: auto; width: 200px; border: 1px solid black; padding: 20px; } <div class='resizable' onresize="resize(this)" onmousemove="move(this)"> Pure vanilla implementation </div>

只有窗口对象生成“调整大小”事件。我所知道的唯一方法是运行一个间隔计时器,定期检查大小。

令人惊讶的是,尽管这个问题已经存在很久了,但在大多数浏览器中仍然存在这个问题。

正如其他人所说,Chrome 64+现在自带Resize observed,然而,该规范仍在微调中,Chrome目前(截至2019-01-29)落后于最新版本的规范。

我已经在野外看到了一些很好的ResizeObserver腻子,但是,一些没有严格遵循规范,另一些有一些计算问题。

我迫切需要这种行为来创建一些可以在任何应用程序中使用的响应式web组件。为了使他们工作得很好,他们需要随时知道他们的尺寸,所以ResizeObservers听起来很理想,我决定创建一个尽可能严格遵循规范的填充。

回购协议: https://github.com/juggle/resize-observer

演示: https://codesandbox.io/s/myqzvpmmy9