我有下面的样本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>
从长远来看,您将能够使用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
});
};
这篇博文帮助我有效地检测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是我用于组织可重用函数的名称空间/对象。请随意搜索并替换任何您想要的名称。
有一种非常有效的方法来确定元素的大小是否已经改变。
http://marcj.github.io/css-element-queries/
这个库有一个resizessensor类,可以用于调整大小检测。它使用基于事件的方法,所以它非常快,而且不会浪费CPU时间。
例子:
new ResizeSensor(jQuery('#divId'), function(){
console.log('content dimension changed');
});
请不要使用jQuery onresize插件,因为它使用setTimeout()结合在循环中读取DOM clienttheight /clientWidth属性来检查更改。这是令人难以置信的缓慢和不准确,因为它会导致布局抖动。
披露:我与这个库直接相关。
看看这个http://benalman.com/code/projects/jquery-resize/examples/resize/
它有很多例子。尝试调整窗口大小,看看容器元素中的元素是如何调整的。
用js的例子来解释如何让它工作。
看看这小提琴http://jsfiddle.net/sgsqJ/4/
在这个resize()事件中,它被绑定到具有类“test”的元素以及窗口对象
在窗口对象$('.test')的resize回调中调用.resize()。
e.g.
$('#test_div').bind('resize', function(){
console.log('resized');
});
$(window).resize(function(){
$('#test_div').resize();
});
当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>