在 Internet Explorer 中调整事件的大小

如你所知,在 Internet Explorer 中,无论是通过赋值/改变页面元素的高度或样式属性来调整页面元素的大小,还是通过简单地添加一个子元素来调整页面元素的大小,或者其他什么——即使元素的大小调整不会影响 viewport 本身的尺寸。

在我的应用程序中,这会导致一个讨厌的递归,因为在我的 window.resize 处理程序中,我调整了一些 < li > 元素的大小,而这些元素又会重新激活 window.resize 等。同样,这只是 IE 中的一个问题。

有没有办法去 防止在 IE 中响应页面上被调整大小的元素而触发 window.resize?

我还应该提到,我正在使用 jQuery。

63504 次浏览

I couldn't get the resize event to fire when an element resized (only tried in IE8 though).

However what is the target on the event object when you're experiencing this issue, could you do:

$(window).resize(function(e) {
if( e.target != window ) return;
// your stuff here
});

I just discovered another problem which might help you.

I am using jQuery and I have window.resize event to call a function which will re-position the div appended to the body.

Now when I set the LEFT css property of that appended div, the window.resize event get trigger for NO GOOD REASON.

It results in an infinite loop, triggering the window.resize again and again.

The code without fix:

$(window).resize(function(){
var onResize = function(){
//The method which alter some css properties triggers
//window.resize again and it ends in an infinite loop
someMethod();
}
window.clearTimeout(resizeTimeout);
resizeTimeout = window.setTimeout(onResize, 10);
});

Solution:

var winWidth = $(window).width(),
winHeight = $(window).height();


$(window).resize(function(){
var onResize = function(){
//The method which alter some css properties triggers
//window.resize again and it ends in an infinite loop
someMethod();
}


//New height and width
var winNewWidth = $(window).width(),
winNewHeight = $(window).height();


// compare the new height and width with old one
if(winWidth!=winNewWidth || winHeight!=winNewHeight){
window.clearTimeout(resizeTimeout);
resizeTimeout = window.setTimeout(onResize, 10);
}
//Update the width and height
winWidth = winNewWidth;
winHeight = winNewHeight;
});

So basically it will check if the height or width is changed (which will happen ONLY when you actually resize with window).

I ran into this problem today and decided to put the following at the top of my global included javascript file:

var savedHeight = 0;
var savedWidth = 0;
Event.observe(window, 'resize', function (e) {
if (window.innerHeight == savedHeight &&
window.innerWidth == savedWidth) { e.stop(); }
savedHeight = window.innerHeight;
savedWidth = window.innerWidth;
});

That requires Prototype, by the way.

My patch:

<!--[if lte IE 7]>
<script type="text/javascript">
window.onresize = null;       // patch to prevent infinite loop in IE6 and IE7
</script>
<![endif]-->

I solved it by unbinding the resize function, rebuilding the page and then binding the resize function again:

function rebuild() {
$(window).unbind('resize');
/* do stuff here */
$(window).bind('resize',rebuild);
}


$(window).bind('resize',rebuild);

EDIT

Bind and unbind don't go well with IE8. Though Microsoft even gave up on IE8 you might want to try this (untested!):

function rebuild(){
if(!window.resizing) return false;
window.resizing=true;
/* do stuff here */
window.resizing=false;
}


window.resizing=false;
document.body.onresize=rebuild;

this made sense to me and seems to work in IE7 and above:

    //variables to confirm window height and width
var lastWindowHeight = $(window).height();
var lastWindowWidth = $(window).width();


$(window).resize(function() {


//confirm window was actually resized
if($(window).height()!=lastWindowHeight || $(window).width()!=lastWindowWidth){


//set this windows size
lastWindowHeight = $(window).height();
lastWindowWidth = $(window).width();


//call my function
myfunction();




}
});
$(window).resize(function(event)
{
if (typeof event.target.tagName == 'undefined')
{
// ...
}
});

A mix of the unbind / bind method with a delayed call. 它可以在Internet Explorer 8及更低版本中运行,防止在版本6和7上出现Evil循环和挂起。

function resizeViewport()
{
// Unbind and rebind only for IE < 9
var isOldIE = document.all && !document.getElementsByClassName;


if( isOldIE )
$(window).unbind( 'resize', resizeViewport );


// ...


if( isOldIE )
{
setTimeout(function(){
$(window).resize( resizeViewport );
}, 100);
}
}


$(window).resize( resizeViewport );

Bind your resize listener with .one() so that it unbinds itself after firing. Then you can do anything you want, so long as at the end you rebind the resize listener. I found the easiest way to do this is by putting the resize listener in an anonymous function like so:

var resizeListener = function(){
$(window).one("resize",function(){ //unbinds itself every time it fires


//resize things


setTimeout(resizeListener,100); //rebinds itself after 100ms
});
}
resizeListener();

You don't technically need the setTimeout wrapped around the resizeListener() but I'd threw it in there as a just-in-case and for some extra throttling.

@AamirAfridi.com's answer solved my problem.

It's a good idea to write a common function to solve such stuff:

function onWindowResize(callback) {
var width = $(window).width(),
height = $(window).height();


$(window).resize(function() {
var newWidth = $(window).width(),
newHeight = $(window).height();


if (newWidth !== width || newHeight !== height) {
width = newWidth;
height = newHeight;
callback();
}
});
}

Use it like this, and you don't have to worry about the different behavior in IE any more:

onWindowResize(function() {
// do something
});

It is up to the how contents are on the resize event.

I figured out the above solves only when a page consists of static contents, not dynamically rendered ones. In the dynamic case where the existing contents will be re-rendered by some trigger event like a contents reload function, we need to use $(document).width() or $(document).height() instead.

This is because of scroll bar of the window. If a page has the scroll bar and the main contents will be re-rendered by clicking a button “Reload”, the scroll bar disappears on the event. In that case, $(window).width() or $(window).height() is changed by the contents rendering, not by the actual window resizing.

You can try this:

Constructor:

this.clientWidth = null;
this.clientHeight = null;

Some function:

var clientWidth = window.innerWidth || document.documentElement.clientWidth;
var clientHeight = window.innerHeight || document.documentElement.clientHeight;
if (clientWidth != this.clientWidth || clientHeight != this.clientHeight ) {
this.clientWidth = clientWidth;
this.clientHeight = clientHeight;


... YOUR CODE ...
}

For Internet Explorer, Chrome, Firefox, Opera, and Safari:

window.innerHeight - the inner height of the browser window
window.innerWidth - the inner width of the browser window

For Internet Explorer 8, 7, 6, 5:

document.documentElement.clientHeight
document.documentElement.clientWidth
or
document.body.clientHeight
document.body.clientWidth
(function ($){
//if ie8 -> return;
var lastHeight = 0;
var lastWidth = 0;
$(window).resize(function(event){
if (window.innerHeight == lastHeight && window.innerWidth == lastWidth)
{ event.stopImmediatePropagation(); }
lastHeight = window.innerHeight;
lastHeight = window.innerWidth;
});
})();

does the trick for me...

<pre>






var cont = 0;
var tmRsize = 100;
var lastWindowWidth = $(window).width();
var lastWindowHeight = $(window).height();


/*****redimensionamiento**********/
$(window).resize(function()
{
if($(window).width() != lastWindowWidth || $(window).height() != lastWindowHeight)
{
clearTimeout(this.id);
this.tiempo = tmRsize;
this.id = setTimeout(doResize, this.tiempo);
}
});


function doResize()
{
lastWindowWidth = $(window).width();
lastWindowHeight = $(window).height();


$('#destino_1').html(cont++);
}

Here's how i deal with finding out if the resize event was fired by an element or by really resizing the window:

If the event's target.nodeType doesn't exist, it is most likely the window, as any other element on the page would have a nodeType.

So here's the pseudo-code (using jQuery) with the added check:

$(window).resize(function(event){
if ( $(event.target.nodeType).length == 0 ){
// Anything here is run when the window was resized
// not executed when an element triggered the resize
}
});