Подія зміни розміру вікна JavaScript


616

Як я можу підключитися до події зміни розміру вікна браузера?

Існує спосіб прослуховування jQuery для подій розміру, але я вважаю за краще не вносити його у свій проект лише для однієї цієї вимоги.


8
Дякую всім. Мене не хвилює IE, я більше думав про зміну розміру для опери на мобільному телефоні.
Мертвий рахунок

Відповіді:


641

jQuery просто завершує стандартну resizeподію DOM, наприклад.

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

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


226
Один із потенційних проблем із цим методом полягає в тому, що ви переосмислюєте подію, і тому ви не можете приєднати до дії кілька дій. Комбо addEventListener / attachEvent - це найкращий спосіб зробити так, щоб ваша програма відтворювала JavaScript з будь-яким іншим сценарієм, який може виконуватися на сторінці.
MyItchyChin

4
var onresize = window.onresize; window.onresize = функція (подія) {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 */ });
Derk Jan Speelman

560

По-перше, я знаю, що addEventListenerметод був згаданий у коментарях вище, але я не бачив жодного коду. Оскільки це кращий підхід, ось він:

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

Ось робочий зразок .


63
Це найпростіша відповідь.
jacoviza

7
Здається, найкраща відповідь, тому що ваше не перезаписує window.onresize подія :-)
Джеймс Харрінгтон

27
У цьому прикладі багато людей додають слухачів анонімних подій, як ви, але це не дуже хороша практика, оскільки такий підхід унеможливлює видалення цих слухачів пізніше. Це не було проблемою, оскільки веб-сторінки в будь-якому випадку були недовгими, але в цей день і вік AJAX, RIA та SPA-центр це стає одним. Нам потрібен спосіб управління життєвим циклом слухачів подій. Таким чином, було б краще розділити функцію слухача на окрему функцію, щоб потім її можна було видалити removeEventListener.
Штійн де Вітт

6
чому всі не можуть відповісти так без всякого пуху
шановно

2
Я думаю, що тут є правда і в відповідях Стийна де Вітта, і у відповідях чемодани. Іноді ви дбаєте про видалення слухачів подій, але якщо ви цього не зробите, додавання всього цього додаткового коду, як у наведеному вище прикладі, є непотрібним і може як розмити, так і менше читати. На мою думку, якщо ви не уявляєте причину необхідності видаляти слухача, такий підхід є найкращим рішенням. Ви завжди можете переписати його пізніше, якщо необхідно. На мій досвід, ці потреби виникають лише у конкретних ситуаціях.
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
Це мала бути прийнятою відповіддю. Перевищення величини збільшення - це лише погана практика.
Tiberiu-Ionuț Stan

8
га, що з усіма зайвими нульовими чеками? намагаєтесь працювати в IE 4.5 чи щось?
FlavorScape

1
І вам цікаво, як мені викликати цю функцію для отримання подій зміни розміру вікна? Ось як: addEvent (вікно, "розмір", function_reference); :)
oabarca

6
Зауважте, що станом на IE 11 attachEventбільше не підтримується. Бажаний шлях до майбутнього addEventListener.
Лук

6
Будьте обережні elem == undefined. Можливо (хоча й малоймовірно), що "невизначений" локально визначається як щось інше. stackoverflow.com/questions/8175673/…
Лук

32

Подія зміни розміру ніколи не повинна використовуватися безпосередньо, оскільки вона запускається постійно під час зміни розміру.

Використовуйте функцію дебютації, щоб зменшити надлишки викликів.

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

Ось загальна дебютація, що плаває по мережі, хоча шукайте більш просунуті, як представники в квартирі.

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);

Ось невеличка бібліотека, яку я зібрав, щоб акуратно подбати про це.


Я ціную інформацію про: debounce (тепер це здається неоціненною концепцією / функцією, хоча я раніше чинив опір використанню тайм-аутів таким чином), lodash (хоча я особисто не переконаний) і вирішення двозначності щодо того, чи слід використовувати addEvent як резервний до addEventListener (лише тому, що старі відповіді насправді прямо не стосуються коментарів щодо цього)
wunth

5
FYI, оскільки ви використовуєте функцію позначення стрілок ES6, внутрішня функція повинна мати (...arguments) => {...}(або ...argsдля меншої плутанини), оскільки argumentsзмінна вже не доступна їх області.
кодератчет

Я цілком усвідомлюю, що фрагмент - це не мій код, це лише приклад.
frontsideup

Відмінна відповідь, проблеми з розміром парфуму потрібно вирішити! Дебютування - це варіант, інше - просте дроселювання (що може бути дорогою, якщо вам потрібен інтерфейс для зміни розміру в "кроках"). Дивіться приклади bencentra.com/code/2015/02/27/optimizing-window-resize.html
Robin Métral

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.

ПРИМІТКА: Новий параметр до 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 році.
Влад Нікула

@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; скоріше додайте нову подію. Дивіться відповідь Джондлма.
Лук

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
Євгенія Горба

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();

на об'єкт події, переданий як перший аргумент події зміни розміру. Наприклад:

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_];
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.