JavaScript窗口调整大小事件


Answers:


641

jQuery只是包装了标准的resizeDOM事件,例如。

window.onresize = function(event) {
    ...
};

jQuery 可以做一些工作来确保在所有浏览器中一致地触发resize事件,但是我不确定是否有任何浏览器有所不同,但是我建议您在Firefox,Safari和IE中进行测试。


226
这种方法的一个潜在陷阱是您要覆盖事件,因此不能将多个操作附加到事件。addEventListener / attachEvent组合是使javascript与页面上可能正在执行的任何其他脚本友好播放的最佳方法。
MyItchyChin

4
var onresize = window.onresize; window.onresize = function(event){if(typeof onresize ==='function')onresize(); / ** ... * /}
SubOne 2012年

230
window.addEventListener('resize', function(){}, true);
WebWanderer 2014年

16
@SubOne是一个永远不要做的完美示例。
尤金·潘科夫

28
ECMAScript 6window.onresize = () => { /* code */ };或更好:window.addEventListener('resize', () => { /* code */ });
Derk Jan Speelman

559

首先,我知道 addEventListener上面的注释中已经提到了方法,但是我没有看到任何代码。由于这是首选方法,因此它是:

window.addEventListener('resize', function(event){
  // do stuff here
});

这里的工作示例


63
这是最直接的答案。
jacoviza

7
听起来是最好的答案,因为您没有覆盖window.onresize事件:-)
James Harrington

27
许多人像在此示例中一样添加匿名事件侦听器,但这并不是一个好习惯,因为这种方法使以后无法删除这些侦听器成为可能。以前这没问题,因为网页无论如何都是短暂的,但是在当今的AJAX和RIA和SPA时代,它正在成为一个。我们需要一种方法来管理事件侦听器的生命周期。因此,最好将侦听器函数分解为一个单独的函数,以便以后可以使用将其删除removeEventListener
Stijn de Witt

6
为什么每个人都不能没有所有的绒毛就这样回答
魁北克省

2
我认为Stijn de Witt和quequeful的答案都是真实的。有时您会关心删除事件侦听器,但如果您不这样做,则不必像上面的示例一样添加所有额外的代码,这既会使人肿又使可读性降低。我认为,如果您没有想到需要删除监听器的理由,则此方法是最佳解决方案。如有必要,您以后随时可以重写它。以我的经验,这些需求仅在特定情况下出现。
cazort

525

切勿覆盖window.onresize函数。

而是,创建一个将事件侦听器添加到对象或元素的函数。这会检查并防止侦听器不起作用,然后作为最后手段重写该对象的功能。这是在jQuery之类的库中使用的首选方法。

object:元素或窗口对象
type:调整大小,滚动(事件类型)
callback:函数参考

var addEvent = function(object, type, callback) {
    if (object == null || typeof(object) == 'undefined') return;
    if (object.addEventListener) {
        object.addEventListener(type, callback, false);
    } else if (object.attachEvent) {
        object.attachEvent("on" + type, callback);
    } else {
        object["on"+type] = callback;
    }
};

然后使用是这样的:

addEvent(window, "resize", function_reference);

或具有匿名功能:

addEvent(window, "resize", function(event) {
  console.log('resized');
});

100
这应该是公认的答案。覆盖onresize只是不好的做法。
Tiberiu-Ionuț Stan,2012年

8
呵呵,所有额外的null检查是怎么回事?试图在IE 4.5之类的东西中工作?
FlavorScape 2012年

1
您想知道如何调用此函数来接收窗口大小调整事件吗?方法如下:addEvent(window,“ resize”,function_reference); :)
oabarca 2014年

6
请注意,从IE 11开始,attachEvent不再受支持。未来的首选方式是addEventListener
路加福音

6
请注意elem == undefined。有可能(尽管不太可能)在本地将“未定义”定义为其他内容。stackoverflow.com/questions/8175673/…–
路加福音

32

调整大小事件永远不要直接使用,因为它在调整大小时会连续触发。

使用去抖动功能来减轻过多的呼叫。

window.addEventListener('resize',debounce(handler, delay, immediate),false);

这是一种常见的在网上浮动的反跳,尽管确实会在lodash中寻找更高级的反跳。

const debounce = (func, wait, immediate) => {
    var timeout;
    return () => {
        const context = this, args = arguments;
        const later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        const callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};

可以这样使用...

window.addEventListener('resize', debounce(() => console.log('hello'),
200, false), false);

每200ms发射一次就不会超过一次。

对于移动方向更改,请使用:

window.addEventListener('orientationchange', () => console.log('hello'), false);

我整理了一个小图书馆来妥善处理这个问题。


我很欣赏以下信息:防抖动(即使我以前拒绝以这种方式使用超时,它现在仍然是非常宝贵的概念/功能),lodash(尽管我个人并不相信)并解决了关于是否使用addEvent作为后备方式的歧义对addEventListener(只是因为旧的答案,没有真正明确提出这方面的意见)
wunth

5
仅供参考,因为您使用的是ES6箭头功能符号,所以内部函数需要具有(...arguments) => {...}(或...args为了减少混淆),因为该arguments变量在其作用域中不再可用。
coderatchet

我完全知道,代码片段不是我的代码,而只是作为示例。
frontsideup

很好的答案,调整尺寸的性能问题需要解决!防弹跳是一种选择,另一种是简单的限制(如果您需要按“步骤”调整UI的大小,则可能是这样)。见bencentra.com/code/2015/02/27/optimizing-window-resize.html的例子
罗宾梅特拉尔

24

2018年以上的解决方案:

您应该使用ResizeObserver。它是浏览器本地解决方案,其性能要比使用resize事件好得多。此外,它不仅支持on事件,document而且还支持任意事件elements

var ro = new ResizeObserver( entries => {
  for (let entry of entries) {
    const cr = entry.contentRect;
    console.log('Element:', entry.target);
    console.log(`Element size: ${cr.width}px x ${cr.height}px`);
    console.log(`Element padding: ${cr.top}px ; ${cr.left}px`);
  }
});

// Observe one or multiple elements
ro.observe(someElement);

目前,Firefox,Chrome和Safari支持它。对于其他(或更旧的)浏览器,您必须使用polyfill


仍然是2020年imo的最佳答案
Jesse Reza Khorasanee


16

我确实相信@Alex V已经提供了正确的答案,但是答案确实需要一些现代化,因为它已经超过5年了。

有两个主要问题:

  1. 切勿将其object用作参数名称。这是一个保留字。话虽如此,@Alex V提供的功能将无法在中使用strict mode

  2. 如果使用该方法addEvent,@ Alex V提供的函数不会返回。应该在函数中添加另一个参数以允许这样做。event objectaddEventListeneraddEvent

注意:addEvent已将新参数设为可选参数,以便迁移到此新功能版本不会中断对该功能的任何先前调用。将支持所有传统用途。

这是addEvent具有这些更改的更新功能:

/*
    function: addEvent

    @param: obj         (Object)(Required)

        -   The object which you wish
            to attach your event to.

    @param: type        (String)(Required)

        -   The type of event you
            wish to establish.

    @param: callback    (Function)(Required)

        -   The method you wish
            to be called by your
            event listener.

    @param: eventReturn (Boolean)(Optional)

        -   Whether you want the
            event object returned
            to your callback method.
*/
var addEvent = function(obj, type, callback, eventReturn)
{
    if(obj == null || typeof obj === 'undefined')
        return;

    if(obj.addEventListener)
        obj.addEventListener(type, callback, eventReturn ? true : false);
    else if(obj.attachEvent)
        obj.attachEvent("on" + type, callback);
    else
        obj["on" + type] = callback;
};

对新addEvent函数的示例调用:

var watch = function(evt)
{
    /*
        Older browser versions may return evt.srcElement
        Newer browser versions should return evt.currentTarget
    */
    var dimensions = {
        height: (evt.srcElement || evt.currentTarget).innerHeight,
        width: (evt.srcElement || evt.currentTarget).innerWidth
    };
};

addEvent(window, 'resize', watch, true);

我会认为attachEvent在2017
。– Vlad Nicula

@VladNicula我同意,但是这个答案已经两年了。
WebWanderer

12

感谢您在http://mbccs.blogspot.com/2007/11/fixing-window-resize-event-in-ie.html中引用我的博客文章。

尽管您可以连接到标准窗口调整大小事件,但您会发现在IE中,该事件每X触发一次,每Y轴移动触发一次,导致触发大量事件,这可能会产生性能如果渲染是一项繁重的任务,则会对您的网站产生影响。

我的方法涉及一个短暂的超时,该超时将在后续事件中取消,以便在用户完成调整窗口大小之前,该事件不会冒泡到您的代码中。


7
window.onresize = function() {
    // your code
};

22
正如上面的许多评论所言,最好不要覆盖onresize函数。而是添加一个新事件。请参阅Jondlm的答案。
路加福音

6

以下博客文章可能对您有用:在IE中修复窗口调整大小事件

它提供了以下代码:

Sys.Application.add_load(function(sender, args) {
    $addHandler(window, 'resize', window_resize);
});

var resizeTimeoutId;

function window_resize(e) {
     window.clearTimeout(resizeTimeoutId);
     resizeTimeoutId = window.setTimeout('doResizeCode();', 10);
}

6
这一个是只适用于ASP.NET应用程序
叶夫根Gorb

2

如果您只想调整窗口和窗口的大小,则上面已经提到的解决方案将起作用。但是,如果您希望将调整大小传播到子元素,则需要自己传播事件。这是一些示例代码:

window.addEventListener("resize", function () {
  var recResizeElement = function (root) {
    Array.prototype.forEach.call(root.childNodes, function (el) {

      var resizeEvent = document.createEvent("HTMLEvents");
      resizeEvent.initEvent("resize", false, true);
      var propagate = el.dispatchEvent(resizeEvent);

      if (propagate)
        recResizeElement(el);
    });
  };
  recResizeElement(document.body);
});

请注意,子元素可以调用

 event.preventDefault();

在作为调整大小事件的第一个Arg传入的事件对象上。例如:

var child1 = document.getElementById("child1");
child1.addEventListener("resize", function (event) {
  ...
  event.preventDefault();
});

1
<script language="javascript">
    window.onresize = function() {
    document.getElementById('ctl00_ContentPlaceHolder1_Accordion1').style.height = '100%';
} 

</script>

1
var EM = new events_managment();

EM.addEvent(window, 'resize', function(win,doc, event_){
    console.log('resized');
    //EM.removeEvent(win,doc, event_);
});

function events_managment(){
    this.events = {};
    this.addEvent = function(node, event_, func){
        if(node.addEventListener){
            if(event_ in this.events){
                node.addEventListener(event_, function(){
                    func(node, event_);
                    this.events[event_](win_doc, event_);
                }, true);
            }else{
                node.addEventListener(event_, function(){
                    func(node, event_);
                }, true);
            }
            this.events[event_] = func;
        }else if(node.attachEvent){

            var ie_event = 'on' + event_;
            if(ie_event in this.events){
                node.attachEvent(ie_event, function(){
                    func(node, ie_event);
                    this.events[ie_event]();
                });
            }else{
                node.attachEvent(ie_event, function(){
                    func(node, ie_event);
                });
            }
            this.events[ie_event] = func;
        }
    }
    this.removeEvent = function(node, event_){
        if(node.removeEventListener){
            node.removeEventListener(event_, this.events[event_], true);
            this.events[event_] = null;
            delete this.events[event_];
        }else if(node.detachEvent){
            node.detachEvent(event_, this.events[event_]);
            this.events[event_] = null;
            delete this.events[event_];
        }
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.