方向改变后的移动视口高度

问题描述 投票:25回答:9

我正在为orientationchange事件附上一个听众:

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

我需要在orientationchange之后获得文档的高度。但是,事件在旋转完成之前触发。因此,记录的高度反映了实际方向变化之前的状态。

如何在完成方向更改后注册允许我捕获元素尺寸的事件?

javascript html5 mobile viewport orientation-changes
9个回答
14
投票

无法捕获方向更改事件的结束,因为方向更改的处理因浏览器而异。在最可靠和最快速的检测方向变化结束方式之间取得平衡需要比赛间隔和超时。

听众附在orientationchange上。调用侦听器会启动一个间隔。间隔是跟踪window.innerWidthwindow.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的实现,该实现扩展了上述逻辑。


14
投票

Gajus'和burtelli的解决方案非常强大,但开销很高。这是一个使用requestAnimationFrame在2017年相当快的超薄版本:

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

14
投票

使用resize事件

resize事件将在orientationchange之后包含适当的宽度和高度,但您不希望侦听所有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
    });
});

不要使用超时

超时不可靠 - 某些设备无法在您的硬编码超时内捕获其方向变化;这可能是出于不可预见的原因,或者因为设备很慢。快速设备将在代码中反向产生不必要的延迟。


9
投票

方向变化需要延迟以获得新的高度和宽度。这有80%的时间都有效。

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

2
投票

我使用了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;

立刻得到内心的高度。希望这有助于某人!


1
投票

我也遇到了同样的问题。所以我最终使用:

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

1
投票

这是一个实验性功能,在屏幕方向改变后给出正确的innerHeight和innerWidth。

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

我认为监听窗口调整大小是实现屏幕方向更改逻辑的最安全的方法。


1
投票

重要的是要注意,orientationchange不会在更改后获得高度,而是在之前。使用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);
    });
});

-1
投票

对于那些只想在innerHeight之后的窗口对象的orientationchange的人有一个简单的解决方案。使用window.innerWidth。在innerWidth事件期间的orientationchangeinnerHeight完成后的orientationchange

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

我不确定是否在两个90度步骤中进行180度变化。在开发人员工具的帮助下无法在浏览器中模拟它。但是如果你想要防止完全旋转180度,270度或360度,应该可以使用screen.orientation.angle计算角度并使用正确的高度和宽度。活动期间的screen.orientation.angleorientationchange事件的目标角度。

© www.soinside.com 2019 - 2024. All rights reserved.