在Gecko XUL体系里,控件元素(button, label等)除了window之外是没有resize事件的,甚至到最近的31.0版本仍没有支持,我估计以后也很难见到元素的resize事件了。因为Mozilla的人当初设计XUL的时候,定义了hbox/vbox元素以及flex属性,甚至支持overflow和text-overflow样式,就是为了让开发人员少操心元素的尺寸变化问题,如果过分关注元素的resize事件,他们一定会说是开发人员自己的思路不对。但有时我在开发自己的扩展时,又不得不去关心元素的尺寸,比如一个vbox,里面有一些子元素,当这个vbox宽度小于一定值时,里面的子元素会在显示和排列方式上出现一些变化。这种情况下,就不得不想点办法来监控元素的尺寸了。
我想到的是最笨的办法,用计时器,interval尽可能小一点,但也不要太小,50毫秒差不多,每个时钟周期去检测元素的宽高,发现有变化时通知出去。为了让这个功能形成一个完整的模块,我用到了XBL,代码如下:
<binding id="resizemonitor">
<implementation>
<field name="mTargetSize">null</field>
<field name="mMonitorInterval">null</field>
<field name="mIntervalTime">50</field>
<constructor><![CDATA[
this.mTargetSize = {
width: 0,
height: 0
};
this.mIntervalTime = parseInt(this.getAttribute("interval"), 10);
if (!mIntervalTime) {
mIntervalTime = 50;
}
var attachType = this.getAttribute("attachType");
if (attachType == "parent") {
this.attach(this.parentNode);
} else if (attachType == "id") {
var targetId = this.getAttribute("targetId");
this.attach(document.getElementById(targetId));
}
]]></constructor>
<destructor><![CDATA[
if (this.mMonitorInterval) {
window.clearInterval(this.mMonitorInterval);
this.mMonitorInterval = null;
}
]]></destructor>
<method name="attach">
<parameter name="targetElt"/>
<body><![CDATA[
if (this.mMonitorInterval) {
window.clearInterval(this.mMonitorInterval);
this.mMonitorInterval = null;
}
var me = this;
this.mMonitorInterval = window.setInterval(function() {
if (targetElt.style.display == "none") {
me.mTargetSize = {
width: 0,
height: 0
};
return;
}
var newWidth = targetElt.boxObject.width;
var newHeight = targetElt.boxObject.height;
if (newWidth != me.mTargetSize.width ||
newHeight != me.mTargetSize.height) {
var event = document.createEvent("Events");
event.initEvent("resize", true, true);
event.targetWidth = newWidth;
event.targetHeight = newHeight;
targetElt.dispatchEvent(event);
me.mTargetSize = {
width: newWidth,
height: newHeight
};
}
}, this.mIntervalTime);
]]></body>
</method>
</implementation>
</binding>
在全局样式表中把这个resizemonitor用-moz-binding绑定一下,就可以使用这个元素标签了。可以把它放在所监视的元素的子结点下,也可以把它放到当前文档的任意一个位置,告诉它监控目标的id值就可以了。当发现目标的宽高发生改变,目标元素会触发一个resize事件,这个事件是自定义的。
用法1:
<textbox flex="1">
<resizemonitor attachType="parent" interval="100/>
</textbox>
监控父元素textbox的尺寸变化,若发生改变,textbox将得到一个resize事件,
textbox.addEventListener("resize", function() {
alert("size changed");
});
用法2:
<vbox id="mainbox"/>
<resizemonitor attachType="id" targetId="mainbox"/>
指定监控对象,计时器默认间隔为50毫秒。