DIV的resize事件不响应的解决办法,解决html 的div或其他元素监听 resize事件不生效的问题

在进行H5开发时,有时候需要单独监听一个网页元素的尺寸变化事件,譬如:div的事件,笔者尝试通过如下代码添加监听,结果没有反应:

someDiv.addEventListener('resize', function(event) {
    console.log('div resize');
});

没有反应的原因是:

DIV元素不像window对象,是没有resize事件的,我们无法直接监听DIV的resize事件。

新的浏览器版本已经发布了一个 ResizeObserver  类用来监听网页元素的尺寸变化事件, 但由于该类需要在比较新的浏览器里才能用,在旧一点的浏览器中无法使用。ResizeObserver 要求的Chrome版本至少是 64,在老的浏览器中不能用。

为了解决这个问题,笔者采用间接方法,即通过在要监听尺寸变化的DIV对象中创建一个可以支持resize事件监听的object(实际是iframe)来间接转发resize事件。

本代码短小,可以很方便的复制粘贴到需要的项目中,没有必要独立成一个js模块,兼容jQuery。

具体实现代码如下:

var ResizeHandler = {
	//@private method
	_onResize: function (e) {
		var ele = e.target || e.srcElement;
		var trigger = ele.__resizeTrigger__;
		if (trigger) {
			var listeners = trigger.__z_resizeListeners;
			if (listeners) {
				var size = listeners.length;
				for (var i = 0; i < size; i++) {
					var h = listeners[i];
					var handler = h.handler;
					var context = h.context;
					if (!context) context = trigger;
					if (handler) {
						handler.apply(context, [e]);
					}
					else if(e.type === 'resize') {
						var event = document.createEvent('Event');
						event.initEvent('resize', false, false);
						trigger.dispatchEvent(event);
					}
				}
			}
		}
	},
	//@public method
	addElement : function (ele, handler, context) {
		var listeners = ele.__z_resizeListeners;
		if (!listeners) {
			listeners = [];
			ele.__z_resizeListeners = listeners;

			if (getComputedStyle(ele, null).position === 'static') {
				ele.style.position = 'relative';
			}
			// create resize Detector object
			var obj = document.createElement('object');
			obj.resizer = this;
			obj.__resizeElement__ = ele;
			obj.setAttribute('style','display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; opacity: 0; pointer-events: none; z-index: -9999;');
			obj.type = 'text/html';
			obj.data = 'about:blank';
			obj.onload = function (evt) {
					this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__;
					this.contentDocument.defaultView.addEventListener('resize', this.resizer._onResize);
				};
			ele.appendChild(obj);
			
			ele.__resizeDetector__ = obj;
		}
		listeners.push({
			handler: handler,
			context: context
		});
	},
	
	removeElement : function (ele, handler, context) {
		var listeners = ele.__z_resizeListeners;
		if (listeners) {
			var size = listeners.length;
			for (var i = 0; i < size; i++) {
				var h = listeners[i];
				if (h.handler === handler && h.context === context) {
					listeners.splice(i, 1);
					break;
				}
			}
			
			if (listeners.length === 0) {
				var detector = ele.__resizeDetector__;
				if (detector) {
					detector.contentDocument.defaultView.removeEventListener('resize', this._onResize);
					ele.removeChild(detector);
					delete ele.__resizeDetector__;
				}
				delete ele.__z_resizeListeners;
			}
		}
	}
};

方法说明如下: 

addElement : function (ele, handler, context)
removeElement : function (ele, handler, context)

参数说明 

ele 为要添加resize事件的元素,不能省略,必须是实际存在的HTML dom对象。

handler 为事件处理器回调,如果省略,则分派消息,即通过 对元素调用 addEventListener 来添加事件回调,否者之间调用指定的回调;

context:为回调函数的this指针,如果省略,则为元素dom对象

1)通过 ResizeHandler  addElement 方法可以添加一个元素与其对应的resize 事件处理回调;
2)通过 removeElement 方法移除需要监听的元素的事件与回调;
3)可以添加无限个元素/事件处理函数 对
4)一个元素也可以添加多个事件处理回调
其中 context 参数为 回调函数的this 指针绑定的对象,如果没有提供,则回调函数的this指针就是元素本身。
注意:如果在调用 addElement  函数时不给与处理函数handler参数 ,则会向该元素分派resize事件,这样后续就可以通过元素的 addEventListener('resize' , xxx) 来添加事件处理函数了,这种方式也可以支持jQuery的  .on('resize', xxx(event)) 方法来监听该元素的resize事件了。

调用的样本代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Resize Demo</title>

 <style>
  html, body {
   margin: 0;
   padding: 0;
   width: 100%;
   height: 100%;
  }
 
  #resizeDiv {
   width: 60%;
   height: 60%;
   border: 1px solid red;
   margin: 20px;
   position:relative;
  }
 
  button {
   margin: 20px 20px 0;
  }
  
  .resizeInner {
	width: 100%;
	height: 100%;
	left: 0;
	top: 0;
	position: absolute;
  }
 </style>
<script>
var ResizeHandler = {
	//@private method
	_onResize: function (e) {
		var ele = e.target || e.srcElement;
		var trigger = ele.__resizeTrigger__;
		if (trigger) {
			var listeners = trigger.__z_resizeListeners;
			if (listeners) {
				var size = listeners.length;
				for (var i = 0; i < size; i++) {
					var h = listeners[i];
					var handler = h.handler;
					var context = h.context;
					if (!context) context = trigger;
					if (handler) {
						handler.apply(context, [e]);
					}
					else if(e.type === 'resize') {
						var event = document.createEvent('Event');
						event.initEvent('resize', false, false);
						trigger.dispatchEvent(event);
					}
				}
			}
		}
	},
	//@public method
	addElement : function (ele, handler, context) {
		var listeners = ele.__z_resizeListeners;
		if (!listeners) {
			listeners = [];
			ele.__z_resizeListeners = listeners;

			if (getComputedStyle(ele, null).position === 'static') {
				ele.style.position = 'relative';
			}
			// create resize Detector object
			var obj = document.createElement('object');
			obj.resizer = this;
			obj.__resizeElement__ = ele;
			obj.setAttribute('style','display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; opacity: 0; pointer-events: none; z-index: -9999;');
			obj.type = 'text/html';
			obj.data = 'about:blank';
			obj.onload = function (evt) {
					this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__;
					this.contentDocument.defaultView.addEventListener('resize', this.resizer._onResize);
				};
			ele.appendChild(obj);
			
			ele.__resizeDetector__ = obj;
		}
		listeners.push({
			handler: handler,
			context: context
		});
	},
	
	removeElement : function (ele, handler, context) {
		var listeners = ele.__z_resizeListeners;
		if (listeners) {
			var size = listeners.length;
			for (var i = 0; i < size; i++) {
				var h = listeners[i];
				if (h.handler === handler && h.context === context) {
					listeners.splice(i, 1);
					break;
				}
			}
			
			if (listeners.length === 0) {
				var detector = ele.__resizeDetector__;
				if (detector) {
					detector.contentDocument.defaultView.removeEventListener('resize', this._onResize);
					ele.removeChild(detector);
					delete ele.__resizeDetector__;
				}
				delete ele.__z_resizeListeners;
			}
		}
	}
};

</script>
</head>
<body>
<button onclick="addElement()">addElement</button>
<button onclick="removeElement()">removeElement</button>

<button onclick="addEvent()">addEvent</button>
<button onclick="removeEvent()">removeEvent</button>

<button onclick="resize()">Do Resize</button>
<div id="resizeDiv">
	<div class="resizeInner" id="resizeInner">
	</div>
</div>
<script>
var resizeDiv = document.getElementById('resizeDiv');
var oldSize = 60;
function resize() {
	oldSize += 10;
	
	resizeDiv.style.width = oldSize + '%';
	
	if (oldSize >= 90) {
		oldSize = 40;
	}
}
var onElementResize = function (e) {
	console.log("resize");
	alert(this.id);
};
function addElement() {
	var innerDiv = resizeDiv.querySelector('.resizeInner');
    // 这种方式只能通过传入的handler参数 onElementResize 来监听事件,无法通过 addEventListener 方式 来添加事件处理函数
	ResizeHandler.addElement(innerDiv, onElementResize);
}
function removeElement() {
	var innerDiv = resizeDiv.querySelector('.resizeInner');
	
	ResizeHandler.removeElement(innerDiv, onElementResize)
}

// 如果不给与 handler 参数,则可以通过给元素添加 addEventListener('resize',fn) 来监听
// jQuery 可以通过 on/off 来添加或删除元素的 resize 事件处理函数
function addEvent() {
	var innerDiv = resizeDiv.querySelector('.resizeInner');
	ResizeHandler.addElement(innerDiv);
}
function removeEvent() {
	var innerDiv = resizeDiv.querySelector('.resizeInner');
	
	ResizeHandler.removeElement(innerDiv)
}

var innerDiv = resizeDiv.querySelector('.resizeInner');
innerDiv.addEventListener('resize', function(event) {
	console.log('resize event trigger');
});

</script>
</body>
</html>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值