如何检测DIV的维度变化?
我有下面的示例HTML,有一个DIV具有100%的宽度。 它包含一些元素。 在执行窗口大小调整时,内部元素可能被重新定位,并且div的尺寸可能会改变。 我问是否有可能钩住div的尺寸变化事件? 和如何做到这一点? 我目前将callback函数绑定到目标DIV上的jQuery resize事件,但是没有输出控制台日志,如下所示:
<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>
有一个非常有效的方法来确定一个元素的大小是否已经改变。
http://marcj.github.io/css-element-queries/
这个库有一个ResizeSensor
类,可以用来resize。
它使用基于事件的方法,所以速度非常快,不会浪费CPU时间。
例:
new ResizeSensor(jQuery('#divId'), function(){ console.log('content dimension changed'); });
请不要使用jQuery onresize插件,因为它使用setTimeout()
循环来检查更改。
这是不可思议的缓慢,不准确 。
披露:我直接与这个图书馆有关。
你必须在window
对象上绑定resize
事件,而不是在一个通用的html元素上。
你可以使用这个:
$(window).resize(function() { ... });
并在callback函数内,你可以检查你的div
调用的新的宽度
$('.a-selector').width();
所以,你的问题的答案是否定的 ,你不能将resize
事件绑定到一个div。
一个新的标准是Resize Observer API,在Chrome 54
的实验性Web平台function标志后面提供。
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>
看看这个http://benalman.com/code/projects/jquery-resize/examples/resize/
它有各种例子。 尝试调整窗口大小,看看如何调整容器元素内的元素。
用js小提琴解释如何让它工作的例子。
看看这个小提琴http://jsfiddle.net/sgsqJ/4/
在这个resize()事件绑定到一个元素具有类“testing”,也是窗口对象和resizecallback窗口对象$('。testing')。resize()被调用。
例如
$('#test_div').bind('resize', function(){ console.log('resized'); }); $(window).resize(function(){ $('#test_div').resize(); });
最好的解决scheme是使用所谓的元素查询 。 但是,它们不是标准的,没有规范存在 – 唯一的select是使用可用的polyfill /库之一,如果你想要这样做。
元素查询背后的想法是允许页面上的某个容器响应提供给它的空间。 这将允许编写一个组件,然后将其放在页面的任何位置,同时将其内容调整为当前的大小。 无论窗口大小是什么。 这是我们在元素查询和媒体查询之间看到的第一个区别。 大家都希望在某个时候创build一个规范来标准化元素查询(或者达到相同目标的东西),并使它们变得原生,干净,简单和健壮。 大多数人都认为,媒体查询是相当有限的,不利于模块化devise和真正的响应。
有几个用不同的方式解决问题的polyfill /库(可以称为解决方法,而不是解决scheme):
- 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
- 还有一些,我不打算在这里列出,但你可以自由search。 我不能说现在哪个选项是最好的。 你将不得不尝试几个并决定。
我已经看到了类似问题的其他解决scheme。 通常他们使用定时器或Window / viewport的大小,这不是一个真正的解决scheme。 此外,我认为这应该主要在CSS中解决,而不是在JavaScript或HTML。
当MarcJ的解决scheme没有时,我发现这个库工作:
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>
长期以来,您将能够使用ResizeObserver 。
new ResizeObserver(callback).observe(element);
不幸的是,目前在许多浏览器中默认不支持。
同时,您可以使用如下function。 因为大部分的元素大小变化将来自于窗口resize或者改变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 }); };
您可以在resize的情况下使用iframe
或使用contentWindow
或contentDocument
object
。 没有setInterval
或setTimeout
步骤:
- 将你的元素位置设置为
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>
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/
查看更多:
- 粘土 – 它基于
element-resize-event
- 元resize事件
只有窗口对象生成“resize”事件。 我知道做你想做的唯一的方法是运行一个定期检查大小的间隔计时器。
使用Clay.js( https://github.com/zzarcon/clay )检测元素大小的变化非常简单:
var el = new Clay('.element'); el.on('resize', function(size) { console.log(size.height, size.width); });
这篇博文帮助我有效地检测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是一个用于组织可重用函数的名称空间/对象。 随意search和replace名称与任何你想要的。
我的jQuery插件启用所有元素的“resize”事件,而不仅仅是window
。
https://github.com/dustinpoissant/ResizeTriggering
$("#myElement") .resizeTriggering().on("resize", function(e){ // Code to handle resize });
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); });
您可以尝试下面的代码片段中的代码,它使用普通的javascript来涵盖您的需求。 ( 运行代码片段并单击整页链接触发警报,如果要testingdiv的大小 )。
基于这个事实,这是一个100毫秒的
setInterval
,我敢说,我的电脑没有发现太多的CPU饿了。 (在testing时,Chrome的所有打开的选项卡总共占用CPU的0.1%)。 但是,这只是一个div,如果你想为大量的元素做到这一点,那么是的,这可能是非常需要CPU的。你总是可以使用一个点击事件来停止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>
使用Bharat Patil答案只需在你的bindcallback里面返回false来防止最大的堆栈错误,参见下面的例子:
$('#test_div').bind('resize', function(){ console.log('resized'); return false; });
这几乎是最好的答案的一个确切的副本,而不是一个链接,这只是代码的一部分,重要的是,翻译成IMO更易读,更容易理解。 其他一些小的变化包括使用cloneNode(),而不是把html放入一个jsstring。 小东西,但你可以复制和粘贴这个,它会工作。
它的工作方式是让两个不可见的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>
规范中只存在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... }
我认为这是不能做的,但后来我想到了,你可以通过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>