Высота мобильного окна после изменения ориентации
Я прикрепляю слушателя к 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++;
});
Вы можете попробовать это. Этот работает для меня. Но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
событие.