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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12452349/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 07:59:00  来源:igfitidea点击:

Mobile viewport height after orientation change

javascripthtmlmobileviewportorientation-changes

提问by Dan Kanze

I am attaching a listener to the orientationchangeevent:

我正在为orientationchange事件附加一个侦听器:

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

I need to get the height of the document after the orientationchange. However, the event is triggered before the rotation is complete. Therefore, the recorded height reflects the state before the actual orientation change.

我需要在orientationchange. 但是,该事件在轮换完成之前被触发。因此,记录的高度反映了实际方向改变之前的状态。

How do I register an event that would allow me to capture element dimensions after the orientation change has been completed?

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

采纳答案by Dan Kanze

Orientation change needs a delay to pick up on the new heights and widths. This works 80% of the time.

方向变化需要延迟才能适应新的高度和宽度。这在 80% 的情况下都有效。

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

回答by Christopher Bull

Use the resize event

使用调整大小事件

The resizeevent will include the appropriate width and height after an orientationchange, but you do not want to listen for all resize events. Therefore, we add a one-off resize event listener after an orientation change:

调整大小事件将包括一个经过适当的宽度和高度orientationchange,但你不希望监听所有的调整大小事件。因此,我们在方向更改后添加一次性调整大小事件侦听器:

Javascript:

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:

jQuery

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

Do NOT use timeouts

不要使用超时

Timeouts are unreliable - some devices will fail to capture their orientation change within your hard-coded timeouts; this can be for unforeseen reasons, or because the device is slow. Fast devices will inversely have an unnecessary delay in the code.

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

回答by kizzx2

Gajus' and burtelli's solutions are robust but the overhead is high. Here is a slim version that's reasonably fast in 2017, using requestAnimationFrame:

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

Use it like this:

像这样使用它:

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

回答by Gajus

There is no way to capture the end of the orientation change event because handling of the orientation change varies from browser to browser. Drawing a balance between the most reliable and the fastest way to detect the end of orientation change requires racing interval and timeout.

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

A listener is attached to the orientationchange. Invoking the listener starts an interval. The interval is tracking the state of window.innerWidthand window.innerHeight. The orientationchangeendevent is fired when noChangeCountToEndnumber of consequent iterations do not detect a value mutation or after noEndTimeoutmilliseconds, whichever happens first.

侦听器附加到orientationchange. 调用侦听器开始一个间隔。的间隔被跟踪的状态window.innerWidthwindow.innerHeightorientationchangeendnoChangeCountToEnd后续迭代次数未检测到值突变或在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);
    });

I am maintaining an implementation of orientationchangeendthat extends upon the above described logic.

我正在维护一个orientationchangeend扩展到上述逻辑的实现。

回答by burtelli

I used the workaround proposed by Gajus Kuizunas for a while which was reliable albeit a bit slow. Thanks, anyway, it did the job!

我使用了 Gajus Kuizunas 提出的解决方法一段时间,虽然有点慢,但它是可靠的。谢谢,无论如何,它完成了工作!

If you're using Cordova or Phonegap I found a faster solution - just in case someone else faces this problem in the future. This plugin returns the correct width/height values right away: https://github.com/pbakondy/cordova-plugin-screensize

如果您使用 Cordova 或 Phonegap,我找到了一个更快的解决方案 - 以防其他人将来遇到这个问题。此插件立即返回正确的宽度/高度值:https: //github.com/pbakondy/cordova-plugin-screensize

The returned height and width reflect the actual resolution though, so you might have to use window.devicePixelRatio to get viewport pixels. Also the title bar (battery, time etc.) is included in the returned height. I used this callback function initally (onDeviceReady)

不过,返回的高度和宽度反映了实际分辨率,因此您可能必须使用 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);
};

In your orientation change event handler you can then use:

在您的方向更改事件处理程序中,您可以使用:

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

to get the innerHeight right away. Hope this helps someone!

立即获得innerHeight。希望这可以帮助某人!

回答by Coisox

I also faced the same problem. So I ended up using:

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

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

回答by sudazzle

It is an experimental feature and gives the right innerHeight and innerWidth after screen orientation is changed.

这是一项实验性功能,可在屏幕方向更改后提供正确的innerHeight 和innerWidth。

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

I think listening to window resize is the safest way to implement screen orientation change logic.

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

回答by Kevin

It is important to note that orientationchange will not get the height after the change, but rather before. Use resize to accomplish this.

需要注意的是,orientationchange 不会得到改变后的高度,而是得到改变之前的高度。使用调整大小来完成此操作。

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

回答by Meursault

I solved this issue combining a couple of the above solutions. Resize would fire 4-5 times. Using .one, it fired too early. A short time out added to Christopher Bull's solution did the trick.

我结合上述几个解决方案解决了这个问题。调整大小会触发 4-5 次。使用 .one,它触发得太早了。添加到 Christopher Bull 的解决方案中的短暂暂停起到了作用。

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

回答by coderuby

For people who just want the innerHeightof the window object after the orientationchangethere is a simple solution. Use window.innerWidth. The innerWidthduring the orientationchangeevent is the innerHeightafter completion of the orientationchange:

对于那些只想要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);
});

I am not sure if 180-degree changes are done in two 90 degree steps or not. Can't simulate that in the browser with the help of developer tools. But If you want to safeguard against a full 180, 270 or 360 rotation possibility it should be possible to use screen.orientation.angleto calculate the angle and use the correct height and width. The screen.orientation.angleduring the event is the target angle of the orientationchangeevent.

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