如何检测DIV's的维度变化?

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

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>
535198 次浏览

你必须在window对象上绑定resize事件,而不是在一个通用的html元素上。

然后你可以使用这个:

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

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

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

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

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

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

它有很多例子。尝试调整窗口大小,看看容器元素中的元素是如何调整的。

< p > 用js的例子来解释如何让它工作。
看看这个小提琴http://jsfiddle.net/sgsqJ/4/

在这个resize()事件中,它被绑定到一个具有类"test"的元素,也被绑定到窗口对象 在窗口对象$('.test').resize()的调整大小回调中被调用

如。

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


$(window).resize(function(){
$('#test_div').resize();
});

有一种非常有效的方法来确定元素的大小是否已经改变。

< a href = " http://marcj.github。Io /css-element-queries/" rel="nofollow noreferrer">http://marcj.github.io/css-element-queries/

这个库有一个类ResizeSensor,可以用于调整大小检测。
它使用基于事件的方法,所以它非常快,不会浪费CPU时间。

例子:

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

请不要使用jQuery onresize插件,因为它在循环中读取DOM clientHeight/clientWidth属性时使用setTimeout()来检查更改。
这是难以置信的缓慢和不准确,因为它会导致布局抖动

披露:我与这个库直接相关。

规范中只有Window.onResize存在,但你总是可以利用IFrame在DIV中生成新的Window对象。

请检查这个回答。有一个新的小jquery插件,它是便携式的,易于使用。您总是可以检查源代码,看看它是如何完成的。

<!-- (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...
}

我认为这是不可能的,但后来我想了一下,你可以手动调整一个div的大小通过style="resize: both;"为了做到这一点,你必须点击它,所以添加了一个onclick函数来检查元素的高度和宽度,它工作。只有5行纯javascript(当然可以更短) http://codepen.io/anon/pen/eNyyVN < / p >

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

最好的解决方案是使用所谓的元素的查询。然而,它们不是标准的,没有规范存在——如果你想这样做,唯一的选择是使用一个可用的腻子库/库。

元素查询背后的思想是允许页面上的某个容器对提供给它的空间做出响应。这将允许编写一次组件,然后将其放在页面的任何位置,同时它将调整其内容到当前大小。这是我们在元素查询和媒体查询之间看到的第一个区别。每个人都希望在某个时候能够创建一个规范来标准化元素查询(或实现相同目标的东西),并使它们原生、干净、简单和健壮。大多数人都同意媒体查询是非常有限的,对模块化设计和真正的响应性没有帮助。

有一些腻子/库可以用不同的方式解决这个问题(可以称为变通方案而不是解决方案):

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

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

var el = new Clay('.element');


el.on('resize', function(size) {
console.log(size.height, size.width);
});

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

new ResizeObserver(callback).observe(element);

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

同时,您可以像下面这样使用函数。因为,大部分元素大小的变化将来自窗口大小的调整或DOM中的某些更改。你可以用窗口的调整事件监听窗口大小的调整,也可以用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
});
};
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);


});

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

这篇博文帮助我有效地检测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是我用于组织可重用函数的名称空间/对象。请随意搜索并替换任何您想要的名称。

你可以使用iframeobject在调整大小时使用contentWindowcontentDocument。没有setIntervalsetTimeout

的步骤:

  1. 将元素位置设置为relative
  2. 在里面添加一个透明的绝对隐藏IFRAME
  3. 监听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>

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/


看到更多:

我的jQuery插件在所有元素上启用了“resize”事件,而不仅仅是window

https://github.com/dustinpoissant/ResizeTriggering

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

一个更新的标准是Resize Observer api,有很好的浏览器支持。

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://developer.mozilla.org/en-US/docs/Web/API/Resize_Observer_API

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

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

Polyfills: https://github.com/pelotoncycle/resize-observer https://github.com/que-etc/resize-observer-polyfill https://github.com/juggle/resize-observer < / p >

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

基于这是一个100毫秒的setInterval的事实,我敢说我的PC没有发现它太多的CPU饥饿。(0.1%的CPU被用作测试时Chrome中所有打开的选项卡的总和。)但这只是一个div,如果你想为大量的元素这样做,那么是的,它可能是非常CPU饥饿。

无论如何,你总是可以使用一个click事件来停止div-resize 嗅探

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>

你也可以检查小提琴

更新

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>

更新小提琴

使用巴拉特帕蒂尔回答简单地在你的绑定回调中返回false,以防止最大堆栈错误,参见下面的例子:

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

这几乎是顶部答案的精确副本,但不是链接,它只是重要的代码的一部分,翻译成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 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>

ResizeSensor.js是一个巨大库的一部分,但我将它的功能减少到:

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);
});

我不推荐setTimeout()黑客,因为它会降低性能! 相反,你可以使用DOM ResizeObserver方法来监听Div大小的变化

const myObserver = new ResizeObserver(entries => {
// this will get called whenever div dimension changes
entries.forEach(entry => {
console.log('width', entry.contentRect.width);
console.log('height', entry.contentRect.height);
});
});


const someEl = document.querySelector('.some-element');


// start listening to changes
myObserver.observe(someEl);


// later, stop listening to changes
myObserver.disconnect();

旧答案使用MutationObserver:

用于监听HTML元素属性、子树和类的更改:

JS:

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

HTML:

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

这是小提琴..试着改变div大小。


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

这是一个非常老的问题,但我想我会把我的解决方案贴出来。

我试图使用ResizeSensor,因为每个人似乎都有一个相当大的迷恋上它。实现后,我意识到,在底层,元素查询要求有问题的元素有位置relativeabsolute应用到它,这并不适用于我的情况。

我最终用Rxjs interval来处理这个问题,而不是像以前的实现那样直接使用setTimeoutrequestAnimationFrame

间隔的可观察对象的好处在于,你可以修改流,但任何其他可观察对象都可以被处理。对我来说,一个基本的实现就足够了,但是你可以疯狂地做各种各样的合并等等。

在下面的例子中,我正在跟踪内部(绿色)div的宽度变化。它的宽度设置为50%,但max-width为200px。拖动滑块会影响包装器(灰色)div的宽度。你可以看到,只有当内部div的宽度发生变化时,可观察对象才会触发,只有当外部div的宽度小于400px时才会发生这种情况。

const { interval } = rxjs;
const { distinctUntilChanged, map, filter } = rxjs.operators;




const wrapper = document.getElementById('my-wrapper');
const input = document.getElementById('width-input');








function subscribeToResize() {
const timer = interval(100);
const myDiv = document.getElementById('my-div');
const widthElement = document.getElementById('width');
const isMax = document.getElementById('is-max');
  

/*
NOTE: This is the important bit here
*/
timer
.pipe(
map(() => myDiv ? Math.round(myDiv.getBoundingClientRect().width) : 0),
distinctUntilChanged(),
// adding a takeUntil(), here as well would allow cleanup when the component is destroyed
)
.subscribe((width) => {
widthElement.innerHTML = width;
isMax.innerHTML = width === 200 ? 'Max width' : '50% width';


});
}


function defineRange() {
input.min = 200;
input.max = window.innerWidth;
input.step = 10;
input.value = input.max - 50;
}


function bindInputToWrapper() {
input.addEventListener('input', (event) => {
wrapper.style.width = `${event.target.value}px`;
});
}


defineRange();
subscribeToResize();
bindInputToWrapper();
.inner {
width: 50%;
max-width: 200px;
}








/* Aesthetic styles only */


.inner {
background: #16a085;
}


.wrapper {
background: #ecf0f1;
color: white;
margin-top: 24px;
}


.content {
padding: 12px;
}


body {
  

font-family: sans-serif;
font-weight: bold;
}
<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>


<h1>Resize Browser width</h1>


<label for="width-input">Adjust the width of the wrapper element</label>
<div>
<input type="range" id="width-input">
</div>


<div id="my-wrapper" class="wrapper">
<div id="my-div" class="inner">
<div class="content">
Width: <span id="width"></span>px
<div id="is-max"></div>
</div>
</div>
</div>

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

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

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

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

< p >回购: https://github.com/juggle/resize-observer < / p > < p >演示: https://codesandbox.io/s/myqzvpmmy9 < / p >

纯Javascript解决方案,但只有在元素用CSS大小调整按钮调整大小时才有效:

  1. offsetWidthoffsetHeight存储元素大小;
  2. 在此元素上添加onclick事件监听器;
  3. 当触发时,比较当前的offsetWidthoffsetHeight与存储的值,如果不同,执行您想要的操作并更新这些值。

下面是@nkron的简化版本的解决方案,适用于单个元素(而不是@nkron的答案中的元素数组,我不需要复杂性)。

function onResizeElem(element, callback) {
// Save the element we are watching
onResizeElem.watchedElementData = {
element: element,
offsetWidth: element.offsetWidth,
offsetHeight: element.offsetHeight,
callback: callback
};


onResizeElem.checkForChanges = function() {
const data = onResizeElem.watchedElementData;
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 resize event
window.addEventListener('resize', onResizeElem.checkForChanges);


// Listen to the element being checked for width and height changes
onResizeElem.observer = new MutationObserver(onResizeElem.checkForChanges);
onResizeElem.observer.observe(document.body, {
attributes: true,
childList: true,
characterData: true,
subtree: true
});
}

事件监听器和观察者可以通过以下方式删除:

window.removeEventListener('resize', onResizeElem.checkForChanges);
onResizeElem.observer.disconnect();

这是@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>

纯香草的实现。

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>

使用disconnect删除事件监听器:

import { Controller } from "@hotwired/stimulus"


export default class extends Controller {
static targets = ["input", "context", "output"]


connect() {
this.inputObserver = new ResizeObserver(() => { this.resizeInput() })
this.inputObserver.observe(this.inputTarget)
}


disconnect() {
this.inputObserver.disconnect(this.inputTarget)
}


resizeInput() {
const height = this.inputTarget.offsetHeight


this.contextTarget.style.height = `${height}px`
this.outputTarget.style.height = `${height}px`
}
}