Событие изменения размера окна JavaScript

618

Как я могу подключиться к событию изменения размера окна браузера?

Существует способ прослушивания событий изменения размера в jQuery, но я бы предпочел не включать его в свой проект только по одному этому требованию.

Мертвый аккаунт
источник
8
Спасибо всем. Меня не волнует IE, я больше думал о том, как изменить размеры оперы на мобильном телефоне.
Мертвый счет

Ответы:

640

JQuery просто оборачивает стандартное resizeсобытие DOM, например.

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

jQuery может сделать некоторую работу, чтобы гарантировать, что событие resize будет срабатывать согласованно во всех браузерах, но я не уверен, отличается ли какой-либо из браузеров, но я бы посоветовал вам протестировать в Firefox, Safari и IE.

olliej
источник
226
Одним из потенциальных недостатков этого метода является то, что вы переопределяете событие и поэтому не можете прикрепить несколько действий к событию. Комбинация addEventListener / attachEvent - лучший способ сделать ваш javascript удобным для воспроизведения с любым другим скриптом, который может выполняться на странице.
MyItchyChin
4
var onresize = window.onresize; window.onresize = function (event) {if (typeof onresize === 'function') onresize (); / ** ... * /}
SubOne
230
window.addEventListener('resize', function(){}, true);
WebWanderer
16
@SubOne прекрасный пример того, как никогда не следует делать это.
Евгений Панков
28
ECMAScript 6 : window.onresize = () => { /* code */ };или лучше:window.addEventListener('resize', () => { /* code */ });
Дерк Ян
561

Во-первых, я знаю, что addEventListenerметод был упомянут в комментариях выше, но я не видел никакого кода. Поскольку это предпочтительный подход, вот он:

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

Вот рабочий образец .

Jondlm
источник
63
Это самый простой ответ.
Яковиза
7
Звучит как лучший ответ, потому что вы не перезаписываете событие window.onresize :-)
Джеймс Харрингтон
27
Многие люди добавляют анонимных слушателей событий, как вы делаете в этом примере, но это не очень хорошая практика, потому что этот подход делает невозможным удаление этих слушателей позже. Раньше это не было проблемой, потому что веб-страницы были недолговечными, но в наше время AJAX, RIA и SPA стали единым целым. Нам нужен способ управления жизненным циклом слушателей событий. Таким образом, было бы лучше выделить функцию слушателя в отдельную функцию, чтобы ее можно было позже удалить с помощью removeEventListener.
Стейн де Витт
6
почему никто не может ответить так без всякого пуха
утомительно
2
Я думаю, что здесь есть доля правды как Стийна де Витта, так и Куметуа. Иногда вы заботитесь об удалении прослушивателей событий, но в случае, если вы этого не сделаете, добавление всего этого дополнительного кода, как в примере выше, не является необходимым и может как раздуть, так и уменьшить читабельность. На мой взгляд, если вы не представляете причину необходимости удалить слушателя, этот подход является лучшим решением. Вы всегда можете переписать его позже, если это необходимо. По моему опыту, эти потребности возникают только в определенных ситуациях.
cazort
524

Никогда не отменяйте функцию 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');
});
Алекс V
источник
100
Это должен был быть принятый ответ. Переопределение размера - это просто плохая практика.
Tiberiu-Ionuț Stan
8
ха, что со всеми дополнительными нулевыми проверками? пытаться работать в IE 4.5 или что-то?
FlavorScape
1
И вам интересно, как я могу вызвать эту функцию для получения событий изменения размера окна? Вот как это сделать: addEvent (window, "resize", function_reference); :)
oabarca
6
Обратите внимание, что с IE 11 attachEventбольше не поддерживается. Предпочтительный путь на будущее addEventListener.
Люк
6
Будьте осторожны с elem == undefined. Возможно (хотя и маловероятно), что «неопределенный» локально определяется как что-то еще. stackoverflow.com/questions/8175673/…
Люк
32

Событие resize никогда не должно использоваться напрямую, так как оно запускается непрерывно при изменении размера.

Используйте функцию debounce для смягчения лишних вызовов.

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

Вот распространенный дебат, распространяющийся по сети, хотя более продвинутые ищите, как featuerd в 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);

Он никогда не будет срабатывать чаще, чем раз в 200 мс.

Для мобильных изменений ориентации используйте:

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

Вот небольшая библиотека, которую я собрал, чтобы аккуратно позаботиться об этом.

frontsideup
источник
Я ценю информацию о: debounce (теперь это кажется бесценной концепцией / функцией, даже если я раньше не использовал использование тайм-аутов таким образом), lodash (хотя я лично не убежден) и устранение неоднозначности относительно того, использовать ли addEvent как запасной вариант к addEventListener (только потому , что старые ответы не очень четко анализировались комментарии относительно этого)
wunth
5
К вашему сведению, поскольку вы используете функцию обозначения стрелки ES6, внутренняя функция должна иметь (...arguments) => {...}(или ...argsдля меньшего количества путаницы), поскольку argumentsпеременная больше не доступна в своей области видимости.
Coderatchet
Я полностью осознаю, что этот фрагмент не мой код, это просто пример.
frontsideup
Отличный ответ, проблемы перфорирования с изменением размера должны быть решены! Дебюссинг - это вариант, другой - простое регулирование (это может быть хорошим способом, если вам нужно, чтобы ваш пользовательский интерфейс изменял размер в «шагах»). См. Bencentra.com/code/2015/02/27/optimizing-window-resize.html для примеров
Робин Мэтрал
24

Решение для 2018+:

Вы должны использовать ResizeObserver . Это нативное решение для браузера, которое имеет гораздо лучшую производительность, чем использование resizeсобытия. Кроме того, он поддерживает не только событие, 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 поддерживают его . Для других (и более старых) браузеров вы должны использовать полифилл .

ул
источник
И все же лучший ответ в 2020 году
Джесси Реза Хорасани
16

Я верю, что @Alex V уже предоставил правильный ответ, но ответ требует некоторой модернизации, так как ему уже более пяти лет.

Есть два основных вопроса:

  1. Никогда не используйте objectв качестве имени параметра. Это зарезервированное слово. С учетом вышесказанного, функция @Alex V не будет работать в strict mode.

  2. addEventФункция , обеспечиваемая @Alex V не возвращают , event objectесли addEventListenerиспользуется метод. Для этого необходимо добавить еще один параметр addEvent.

ПРИМЕЧАНИЕ. Новый параметр to 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);
WebWanderer
источник
Я бы сказал, что attachEvent больше не актуален в 2017 году.
Влад Никула
@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
};
saravanakumar
источник
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);
}
lakshmanaraj
источник
6
Это применимо только к приложениям ASP.NET
Евгений Горб
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 события resize. Например:

var child1 = document.getElementById("child1");
child1.addEventListener("resize", function (event) {
  ...
  event.preventDefault();
});
rysama
источник
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_];
        }
    }
}
УДИВИТЕЛЬНЫЙ
источник