<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>
#1 楼
有一种非常有效的方法来确定元素的大小是否已更改。http://marcj.github.io/css-element-queries/
此库具有
ResizeSensor
类别,可用于调整大小检测。它使用基于事件的方法,因此该死的速度很快,并且不会浪费CPU时间。示例:
new ResizeSensor(jQuery('#divId'), function(){
console.log('content dimension changed');
});
请不要使用jQuery onresize插件,因为它结合使用
setTimeout()
和循环读取DOM clientHeight
/ clientWidth
属性来检查更改。这真是令人难以置信的缓慢和不准确,因为它会引起布局抖动。公开:我直接与此库关联。
评论
@jake,现已实现IE11支持。
– Marc J. Schmidt
2014年9月8日,12:25
@Aletheios,您应该仔细看看。 requestAnimationFrame不是用于慢速尺寸检测,而是完全相反:它可以平滑所有基于真实事件的大小调整传感器触发的所有极端事件,以节省CPU时间。在github.com/marcj/css-element-queries/blob/master/src/中查看更新的文档。
– Marc J. Schmidt
16 Mar 17 '16 at 17:41
@Aletheios我想您会漏掉一点:setTimeout不仅不准确,而且像地狱般缓慢。用于检查简单布尔值的requestAnimationFrame的速度比setTimeout始终检查DOM属性的速度快几个数量级。在setTimeout旁边还每隔几毫秒调用一次。
– Marc J. Schmidt
16-3-17在19:38
@Orwellophile您显然一无所知。如果您不知道内部答案如何,请停止投票。再次:css-element-query:使用真正的调整大小事件,每次尺寸更改时都会触发该事件。由于您会收到太多事件(例如,拖放操作),因此它添加了requestAnimationFrame检查简单的布尔变量,以将触发的事件平滑降至1 / frame。 jQuery插件:使用setTimeout来检查所有时间的DOM布局道具(clientHeight等),其中每次检查都很慢,但需要经常检查以具有相同的功能。
– Marc J. Schmidt
16-9-27在14:01
@ Aletheios,@ Orwellophile,以及任何可能被他们误导的人:requestAnimationFrame与setTimeout无关,此库不会循环。 requestAnimationFrame仅用于消除/限制调用回调的频率,它不会轮询。理论上,MutationObserver可以起到类似的作用,但与此不同,不能在较旧的浏览器中使用。这是非常聪明的。
–汉城汉城
17年4月26日在2:29
#2 楼
一个新的标准是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
填充物:https:// github .com / WICG / ResizeObserver / issues / 3
Firefox问题:https://bugzil.la/1272409
Safari问题:http://wkb.ug/157743
当前支持:http://caniuse.com/#feat=resizeobserver
评论
尚不适用于生产站点,因为目前只有Chrome支持。但绝对是这里最好的解决方案!顺便说一句,这里是实施状态的快速概述:chromestatus.com/feature/5705346022637568
– Philipp
16/09/10在19:47
@Philipp有一个polyfill。
–丹尼尔·赫尔(Daniel Herr)
16 Sep 15 '23:35
即使在得到此答案的2年后,浏览器的支持也很惨淡:caniuse.com/#search=resizeobserver
–犯罪
18/12/18在17:39
现在可以在Firefox,Chrome,Safari和Opera中使用。
–Explorer
19年11月11日在4:28
现在,所有主要浏览器都支持ResizeObserver。
–有用的角度
5月11日8:10
#3 楼
从长远来看,您将可以使用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
});
};
评论
不幸的是,似乎MutationObserver无法检测Shadow DOM中的更改。
– Ajedi32
15-10-27在14:51
@nkron,不幸的是,如果使用CSS3调整大小,则当用户手动调整大小时可能会发生调整大小。无法捕获此事件。
–起搏器
16-2-19在1:38
@ Ajedi32是的,但是您可以在ShadowDOM内部使用MutationObserver。我的意思是,您可以直接观察元素,而不是像本示例中那样观察身体。实际上,与观察整个身体相比,这更加高效和高效。
–trusktr
16年8月6日在6:58
@ Ajedi32好吧,唯一的问题是,如果Shadow DOM树已关闭,则您将无法访问内部,但是我认为这通常不是您需要做的,并且如果您需要观察像这样的闭树,那么设计中可能会有问题。理想情况下,您只需要观察自己可以访问的元素即可。需要您观察其内部大小的Shadow-DOM组件可能未正确设计。你有一个具体的例子吗?如果是这样,也许我可以帮忙提出一个解决方案(因为我也对此感兴趣,但是还没有示例)。
–trusktr
16年8月6日在7:02
@trusktr我目前没有MCVE,但是基本上任何Shadow DOM元素(由于某些用户输入而可以更改其大小)都足以触发此问题。例如,当单击一个框时,它会展开并带有一些其他信息。请注意,我观察的是页面,而不是单个元素,因为无论页面大小如何,我都想自动向下滚动。 Shadow DOM元素扩展只是页面可能变长的许多可能原因之一。
– Ajedi32
16年8月8日在13:40
#4 楼
您必须将resize
事件绑定到window
对象上,而不是绑定到通用html元素上。然后可以使用此函数:
$(window).resize(function() {
...
});
在回调函数中,您可以检查
div
调用的新宽度$('.a-selector').width();
因此,问题的答案是否定的,您无法绑定
resize
事件到div。评论
这个答案还不够好。如果不调整窗口大小,可能会发生大小更改。完全没有
– vsync
2014年3月16日在0:02
例如,当您有一个splitter元素或仅将一些文本或其他内容附加到该元素时。
–GünterZöchbauer
2014年5月3日在17:02
@anu不正确,您可以通过javascript进行DOM修改,例如将CSS应用于新结构,从而导致不同的布局-每个容器的大小。
– Antoniosssss
18年1月17日在13:30
#5 楼
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);
});
评论
这就是图表js所做的。
– Antoniosssss
18年1月17日在13:12
感谢压缩。我将尝试一下:)
– Tony K.
18年4月13日在20:40
此表达式中缺少一些东西parseInt(getComputedStyle(element))
– GetFree
18年5月7日在18:41
我很困惑“如何让zIndex = parseInt(getComputedStyle(element));”有效?我假设您的意思是:“ let zIndex = parseInt(getComputedStyle(element).zIndex);
–瑞安·巴杜(Ryan Badour)
19年4月1日在15:48
上面的解决方案/代码不会检测所有调整大小的事件(例如,如果将容器调整为固定大小,则不会检测子事件的调整大小。请参阅jsfiddle.net/8md2rfsy/1)。接受的答案有效(取消注释相应的行)。
–newBee
19年4月29日在14:05
#6 楼
我不建议您使用setTimeout()
hack,因为它会降低性能!相反,您可以使用DOM突变观察器来监听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>
这里是小提琴
尝试更改div的大小。
您可以将方法进一步包装在
debounce
方法中,以提高效率。 debounce
将每隔x毫秒触发一次您的方法,而不是每隔一毫秒触发一次DIV调整大小。评论
唯一的问题是,除非元素发生实际突变,否则它不会报告更改。如果元素由于添加了其他元素而调整了大小,则将无法使用。
– Tony K.
18年4月13日在20:40
我同意@TonyK。,这是MutationObserver的唯一问题,现在我正在寻找元素调整大小的库
–Murhaf Sousli
19年6月8日在3:16
@JerryGoyal当div包含标记时,它不起作用。在第一种情况下,不会加载图片,并且div大小设置为0,并且在加载后div大小会更改,但是不会触发观察者
–山多士
1月21日9:18
#7 楼
最好的解决方案是使用所谓的元素查询。但是,它们不是标准的,不存在任何规范-如果您想这样做,唯一的选择是使用一种可用的polyfills /库。元素查询的思想是允许页面上的某个容器以响应提供给它的空间。这将允许编写一次组件,然后将其放在页面上的任何位置,同时它将其内容调整为当前大小。无论窗口大小是多少。这是我们在元素查询和媒体查询之间看到的第一个区别。每个人都希望在某个时候可以创建一个规范,以规范元素查询(或达到相同目标的东西)并使它们本机,干净,简单且健壮。大多数人都认为,媒体查询非常有限,无法帮助模块化设计和真正的响应能力。
有一些polyfills /库以不同方式解决问题(可以称为解决方法,而不是解决方法解决方案):
CSS元素查询-https://github.com/marcj/css-element-queries
BoomQueries-https:// github .com / BoomTownROI / boomqueries
eq.js-https://github.com/Snugug/eq.js
ElementQuery-https://github.com/tysonmatanich / elementQuery
还有更多内容,我不在这里列出,但您可以自由搜索。我无法说出哪个当前可用的选项是最好的。您必须尝试一些并做出决定。
我已经看到了针对类似问题的其他解决方案。通常他们使用计时器或引擎盖下的窗口/视口大小,这不是真正的解决方案。此外,我认为理想情况下,这应该主要在CSS中解决,而不是在javascript或html中解决。
评论
+1用于元素查询,但我不希望很快见到它们。 AFAIK目前甚至还没有规范草案...也许我们其中一个感兴趣的团体应该将其放在一起提交?
–Rob Evans
15年7月14日在14:42
当然,这是个好主意。到达最终版本需要很长时间,需要引起很多注意。对我来说,以一种好的方式设计它似乎并不重要。跨浏览器兼容性,循环依赖项,调试,可读性和维护性等。因此,让我们尽早开始:)
–斯坦
15年7月17日在10:00
@Stan,我认为通过对元素查询的全部内容进行更多说明,可以更好地解决此问题。
–起搏器
16-2-19的1:40
#8 楼
当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>
评论
就是这个。 147行,使用滚动事件。如果您想获得有关如何最好地检测div尺寸变化的完整而真实的答案,请通读此代码。提示:它不是“仅使用此库”。
– Seph Reed
16-10-30在20:22
人们在尝试使用此库之前应该先看一下这个问题。
–路易
16年11月17日在19:34
#9 楼
看看这个http://benalman.com/code/projects/jquery-resize/examples/resize/它有很多示例。尝试调整窗口大小,看看如何调整容器元素内的元素。
js小提琴的示例解释了如何使其工作。
看看这个小提琴http://jsfiddle.net / sgsqJ / 4 /
,其中resize()事件绑定到具有“ test”类的元素,还绑定到窗口对象
,并绑定到窗口对象$('的resize回调中。 test')。resize()被调用。
例如
$('#test_div').bind('resize', function(){
console.log('resized');
});
$(window).resize(function(){
$('#test_div').resize();
});
评论
有趣。 jsfiddle始终在打开检查器的情况下使chrome崩溃,然后单击“添加更多文本”链接。 Firefox抛出“太多递归”错误。
– EricP
2013年9月22日在17:58
请不要使用jQuery的大小调整插件。这确实很慢,而且也不准确。查看我的答案以获得更好的解决方案。
– Marc J. Schmidt
13-10-17在4:03
这不会直接检测尺寸变化。它只是调整大小的事件侦听器的副产品。尺寸变化可以通过许多其他方式发生。
– vsync
2014年3月16日在0:04
如果div的大小调整来自样式或dom的更改,而不是窗口大小调整,该怎么办?
–敬畏
2015年4月10日上午11:46
#10 楼
您可以在调整大小时使用iframe
或object
。不使用contentWindow
或contentDocument
步骤:
将元素位置设置为
setInterval
在透明的绝对隐藏IFRAME中添加
/>听
setTimeout
-relative
事件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/
查看更多:
黏土-基于
IFRAME.contentWindow
element-resize-event
评论
对于不使用jquery的用户,只有在iframe上触发onload事件后,IFRAME.contentWindow才可用。另外,您可能需要添加样式visible:hidden ;,因为iframe可能会将鼠标输入阻止到其后面的元素上(至少在IE中似乎是“浮动”的)。
–詹姆斯·威尔金斯(James Wilkins)
16年6月16日下午5:00
尽管这可行,但这是一个重量级的解决方案,其开销只是创建一个新的浏览上下文以观察大小变化。另外,在某些情况下,更改元素的显示属性也不理想或不可行。
–trusktr
16年8月6日在7:05
同意,这是如上所述的可怕解决方案
– 29er
16-11-15在19:20
怎么写这么可怕的解决方案?
– Aminadav Glickshtein
16年11月15日在19:47
此方法适用于需要动态调整内容大小的视频播放器和音频播放器。我正在使用此方法来调整waveurfer.js输出的大小。
– David Clews
1月24日14:14
#11 楼
仅窗口对象会生成“调整大小”事件。我唯一知道要执行的操作的方法是运行一个间隔计时器,该计时器会定期检查大小。#12 楼
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>
#13 楼
与这个问题一样古老,但是在大多数浏览器中,这仍然是一个问题。正如其他人所说,Chrome 64+现在已随本机一起提供了Resize Observes,但是,该规范仍在微调和Chrome当前(截至2019年1月29日)落后于该规范的最新版本。
我已经看到了很多不错的ResizeObserver填充器,但是其中一些并没有遵循该规范和其他规范都存在一些计算问题。
我非常需要这种行为来创建一些可在任何应用程序中使用的响应式Web组件。为了使它们正常工作,他们需要始终了解它们的尺寸,因此ResizeObservers听起来很理想,我决定创建一个尽可能符合规格的polyfill。
Repo:
https ://github.com/juggle/resize-observer
演示:
https://codesandbox.io/s/myqzvpmmy9
评论
对于任何处理IE11 +浏览器兼容性的人来说,这绝对是一个困扰的答案。
– ekfuhrmann
19年7月22日在19:47
#14 楼
使用Clay.js(https://github.com/zzarcon/clay),检测元素大小的变化非常简单:var el = new Clay('.element');
el.on('resize', function(size) {
console.log(size.height, size.width);
});
评论
鉴于它是您的图书馆,请提供适当的披露。
– jhpratt
18年5月19日在22:28
这对我有用,在ResizeSensor不起作用的情况下,它破坏了我的模态样式。谢谢Zzarcon :)
–Máxima Alekz
18-10-2在14:50
#15 楼
这篇博客文章帮助我有效地检测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是我用来组织可重用函数的名称空间/对象。随时搜索并用您想要的任何名称替换名称。
#16 楼
我的jQuery插件不仅对window
启用了所有元素的“调整大小”事件。https://github.com/dustinpoissant/ResizeTriggering
$("#myElement") .resizeTriggering().on("resize", function(e){
// Code to handle resize
});
评论
您的链接指向的位置不再存在。我已经搜索了插件的名称,并找到了一个与您的描述相对应的页面。由于您似乎是该插件的作者,因此我还编辑了答案的语言,以明确表明这是您的工作。该站点的规则是这样的,当您编写答案时建议使用您开发的内容,则必须明确关系。
–路易
16年11月17日在19:29
这不是一个很好的解决方案,因为您一次又一次地在setTimer中运行某些功能,这意味着即使没有任何反应,浏览器也会不断消耗CPU。便携式计算机和手机所有者受益于仅在采取某些操作(例如使用onScroll事件)时才使用浏览器事件的解决方案。
–罗马Zenka
18年1月23日在16:26
#17 楼
这是@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();
#18 楼
您可以尝试以下代码段中的代码,它使用纯JavaScript满足了您的需求。 (运行代码段,然后单击整页链接以触发div调整大小的警报(如果您要对其进行测试。)。基于
setInterval
为100毫秒的事实,我敢于说我的PC并没有发现它占用过多的CPU。 (在测试时,Chrome中所有打开的标签页使用的CPU总数为0.1%。)。但是再说一次,这仅适用于一个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>
还可以检查小提琴
更新
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>
更新了小提琴
#19 楼
这几乎是最佳答案的精确副本,但它不是链接,而只是重要的代码部分,翻译为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);
}
#20 楼
纯Javascript解决方案,但仅在使用css调整大小按钮调整元素大小时才有效:使用offsetWidth和offsetHeight存储元素大小;
在此元素上添加onclick事件侦听器;
被触发时,将当前
offsetWidth
和offsetHeight
与存储的值进行比较,如果不同,则执行所需操作并更新这些值。#21 楼
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);
});
#22 楼
使用Bharat Patil答案只需在绑定回调内部返回false即可防止最大堆栈错误,请参见以下示例:$('#test_div').bind('resize', function(){
console.log('resized');
return false;
});
#23 楼
这是一个非常老的问题,但是我想我应该对此发布解决方案。我尝试使用
ResizeSensor
,因为每个人似乎对此都有很大的迷恋。在实施之后,我意识到在元素查询的幕后,需要将有问题的元素应用于位置relative
或absolute
,这对我的情况不起作用。我最终处理了此问题使用Rxjs
interval
,而不是像以前的实现那样使用直线setTimeout
或requestAnimationFrame
。 间隔的可观察的风格的好处是您可以修改流,但是可以处理其他任何可观察的对象。对我来说,一个基本的实现就足够了,但是您可能会发疯并进行各种合并等。
在下面的示例中,我正在跟踪内部(绿色)div的宽度变化。它的宽度设置为50%,但最大宽度为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>
#24 楼
规范中仅存在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,那么这是非常无效的解决方案。
–suricactus
15年11月12日在15:04
#25 楼
我以为无法完成,但是后来我想到了,您可以通过style =“ resize:both;”手动调整div的大小。为了做到这一点,您必须单击它,因此添加了一个onclick函数来检查元素的高度和宽度,并且它可以正常工作。仅使用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>
评论
这仅会计算触发事件的点击事件,这不属于问题的要求。
–Rob Evans
15年7月14日在14:39
评论
这将不起作用,因为您正在将resize事件绑定到指定的div元素。但是resize事件将触发窗口,而不触发您元素的窗口。您可以在此处使用setInterval作为可能的解决方案。工作完成后,您始终可以将clearInterval绑定到单击按钮以停止循环。
自2020年以来,ResizeObserver可在除IE之外的所有主要浏览器(Chrome,Safari,Firefox,Edge)中使用。 caniuse.com/#feat=resizeobserver