Высота мобильного окна после изменения ориентации

Я прикрепляю слушателя к orientationchange событие:

window.addEventListener('orientationchange', function () {
    console.log(window.innerHeight);
});

Мне нужно получить высоту документа после orientationchange, Тем не менее, событие запускается до завершения вращения. Поэтому записанная высота отражает состояние до фактического изменения ориентации.

Как зарегистрировать событие, которое позволило бы мне регистрировать размеры элемента после того, как изменение ориентации было завершено?

13 ответов

Решение

Изменение ориентации требует задержки, чтобы подобрать новые высоты и ширины. Это работает в 80% случаев.

window.setTimeout(function() {
    //insert logic with height or width calulations here.
}, 200);

Используйте событие изменения размера

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

Javascript:

window.addEventListener('orientationchange', function() {
    // After orientationchange, add a one-time resize event
    var afterOrientationChange = function() {
        // YOUR POST-ORIENTATION CODE HERE
        // Remove the resize event listener after it has executed
        window.removeEventListener('resize', afterOrientationChange);
    };
    window.addEventListener('resize', afterOrientationChange);
});

JQuery:

$(window).on('orientationchange', function() {
    // After orientationchange, add a one-time resize event
    $(window).one('resize', function() {
        // YOUR POST-ORIENTATION CODE HERE
    });
});

НЕ используйте тайм-ауты

Тайм-ауты ненадежны - некоторые устройства не смогут зафиксировать изменение своей ориентации в течение ваших жестко запрограммированных таймаутов; Это может произойти по непредвиденным причинам или из-за медленной работы устройства. Быстрые устройства будут иметь обратную задержку в коде.

Решения Gajus и Burtelli надежны, но накладные расходы высоки. Вот тонкая версия, которая довольно быстрая в 2017 году, используя requestAnimationFrame:

// Wait until innerheight changes, for max 120 frames
function orientationChanged() {
  const timeout = 120;
  return new window.Promise(function(resolve) {
    const go = (i, height0) => {
      window.innerHeight != height0 || i >= timeout ?
        resolve() :
        window.requestAnimationFrame(() => go(i + 1, height0));
    };
    go(0, window.innerHeight);
  });
}

Используйте это так:

window.addEventListener('orientationchange', function () {
    orientationChanged().then(function() {
      // Profit
    });
});

Невозможно зафиксировать конец события изменения ориентации, поскольку обработка изменения ориентации варьируется от браузера к браузеру. Для установления баланса между самым надежным и самым быстрым способом определения конца изменения ориентации требуются гоночный интервал и тайм-аут.

Слушатель прикреплен к orientationchange, Вызов слушателя начинает интервал. Интервал отслеживания состояния window.innerWidth а также window.innerHeight, orientationchangeend событие происходит, когда noChangeCountToEnd количество последовательных итераций не обнаруживает мутации значения или после noEndTimeout миллисекунды, в зависимости от того, что произойдет раньше.

var noChangeCountToEnd = 100,
    noEndTimeout = 1000;

window
    .addEventListener('orientationchange', function () {
        var interval,
            timeout,
            end,
            lastInnerWidth,
            lastInnerHeight,
            noChangeCount;

        end = function () {
            clearInterval(interval);
            clearTimeout(timeout);

            interval = null;
            timeout = null;

            // "orientationchangeend"
        };

        interval = setInterval(function () {
            if (global.innerWidth === lastInnerWidth && global.innerHeight === lastInnerHeight) {
                noChangeCount++;

                if (noChangeCount === noChangeCountToEnd) {
                    // The interval resolved the issue first.

                    end();
                }
            } else {
                lastInnerWidth = global.innerWidth;
                lastInnerHeight = global.innerHeight;
                noChangeCount = 0;
            }
        });
        timeout = setTimeout(function () {
            // The timeout happened first.

            end();
        }, noEndTimeout);
    });

Я поддерживаю реализацию orientationchangeend это распространяется на вышеописанную логику.

Я решил эту проблему, объединив пару вышеперечисленных решений. Resize сработает 4-5 раз. Используя.one, он сработал слишком рано. Короткий тайм-аут, добавленный к решению Кристофера Булла, помог.

$(window).on('orientationchange', function () {
  $(window).one('resize', function () {
    setTimeout(reference_to_function, 100);
  });
});

Некоторое время я использовал обходной путь, предложенный Gajus Kuizunas, который был надежным, хотя и немного медленным. Спасибо, так или иначе, это сделало работу!

Если вы используете Cordova или Phonegap, я нашел более быстрое решение - на тот случай, если кто-то еще столкнется с этой проблемой в будущем. Этот плагин сразу возвращает правильные значения ширины / высоты: https://github.com/pbakondy/cordova-plugin-screensize

Однако возвращенные высота и ширина отражают фактическое разрешение, поэтому вам может потребоваться использовать window.devicePixelRatio для получения пикселей области просмотра. Также строка заголовка (батарея, время и т. Д.) Включена в возвращаемую высоту. Я использовал эту функцию обратного вызова изначально (onDeviceReady)

var successCallback = function(result){
    var ratio = window.devicePixelRatio;            
    settings.titleBar = result.height/ratio-window.innerHeight; 
    console.log("NEW TITLE BAR HEIGHT: " + settings.titleBar);
};

В обработчике событий изменения ориентации вы можете использовать:

height = result.height/ratio - settings.titleBar;

чтобы получить внутреннюю высоту сразу. Надеюсь, это поможет кому-то!

Как уже упоминал Ramprakash Jagadeesan, существует Resize Observer Api.

Вот как я его использовал:

      const fullSizeImageObserver = new ResizeObserver(entries => {

  for (let entry of entries) {
      const heightAfterRotation = entry.target.clientHeight;
      // Execute code using the new height of the observed element after the device rotation completed.
  };
});

fullSizeImageObserver.observe(document.getElementById("element-to-observe"));

Изменение размера может срабатывать более одного раза. Вы можете обойти это следующим образом:

        for (let entry of entries) {
    if(Math.floor(entry.contentRect.height) === entry.target.clientHeight) { 
      const heightAfterRotation = entry.target.clientHeight;
      // Execute ONCE code using the new height of the observed element after the device rotation completed.
    };
  };

Посетите https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver для получения дополнительной информации и поддержки браузера.

Это экспериментальная функция, которая дает правильные innerHeight и innerWidth после изменения ориентации экрана.

window.screen.orientation.addEventListener('change', function(){
    console.log(window.innerHeight)
})

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

Важно отметить, что ориентация не будет получать высоту после изменения, а скорее до. Используйте resize для достижения этой цели.

$(window).bind('orientationchange', function (e) {
    var windowHeight = $(window).innerHeight();
    console.log('Before Orientation: Height = ' + windowHeight);

    $(window).resize(function () {
        windowHeight = $(window).innerHeight();
        console.log('After Orientation: Height = ' + windowHeight);
    });
});

Я тоже столкнулся с той же проблемой. Итак, я использовал:

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

В 2022 году следующий код поддерживается всеми браузерами и операционными системами:

      let counter=1;
let wih = window.innerHeight;
let wiw = window.innerWidth;
let orientationOnLoad;
let mql = window.matchMedia("(orientation: portrait)");
if(mql.matches) {  
    orientationOnLoad='Portrait';
} else {  
    orientationOnLoad='Landscape';
}
console.log('onload: '+orientationOnLoad+', '+wiw+'x'+wih);

mql.addEventListener('change', function(e) {
    let wih = window.innerHeight;
    let wiw = window.innerWidth;
    if(e.matches) {
        console.log('orientationchange event ('+counter+'): Portrait, '+wiw+'x'+wih);
    }
    else {
        console.log('orientationchange event ('+counter+'): Landscape, '+wiw+'x'+wih);
    }
    counter++;
});

window.matchMedia против screen.ориентация

Вы можете попробовать это. Этот работает для меня. Ноorientationchangeустарела в нескольких браузерах. Пожалуйста, проверьте совместимость.

      window.addEventListener("orientationchange", () => {
  window.addEventListener("resize", () => {
     .... 
     // do you function... () {}
  })
});

Это тоже можно попробовать..

      function setBackgroundImage() {
    .... your fun() .....
}
const myBgContainer = document.querySelector(".bgContainer");

new ResizeObserver(setBackgroundImage).observe(myBgContainer);

Для людей, которые просто хотят innerHeight объекта окна после orientationchange есть простое решение. использование window.innerWidth, innerWidth в течение orientationchange событие innerHeight после завершения orientationchange:

window.addEventListener('orientationchange', function () {
    var innerHeightAfterEvent = window.innerWidth;
    console.log(innerHeightAfterEvent);
    var innerWidthAfterEvent = window.innerHeight;
    console.log(innerWidthAfterEvent);
    console.log(screen.orientation.angle);
});

Я не уверен, сделаны ли изменения на 180 градусов в два шага на 90 градусов или нет. Не могу смоделировать это в браузере с помощью инструментов разработчика. Но если вы хотите защитить от возможности полного вращения на 180, 270 или 360, следует использовать screen.orientation.angle рассчитать угол и использовать правильную высоту и ширину. screen.orientation.angle во время мероприятия является целевым углом orientationchange событие.

Другие вопросы по тегам