43

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

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

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

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

4

10 回答 10

32

使用调整大小事件

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

不要使用超时

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

于 2018-03-20T11:40:59.390 回答
21

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
    });
});
于 2017-06-16T02:11:09.077 回答
16

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

一个监听器附加到orientationchange. 调用侦听器会启动一个间隔。区间跟踪 和 的window.innerWidth状态window.innerHeight。当后续迭代次数未检测到值突变或毫秒后orientationchangeend触发该事件,以先发生者为准。noChangeCountToEndnoEndTimeout

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基于上述逻辑的实现。

于 2014-11-09T14:43:00.243 回答
8

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

window.setTimeout(function() {
    //insert logic with height or width calulations here.
}, 200);
于 2012-09-23T22:47:24.073 回答
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;

立即获得innerHeight。希望这对某人有帮助!

于 2016-01-06T12:26:48.417 回答
2

我结合上述几个解决方案解决了这个问题。调整大小会触发 4-5 次。使用 .one,它启动得太早了。克里斯托弗·布尔的解决方案中添加了一个短暂的时间就可以了。

$(window).on('orientationchange', function () {
  $(window).one('resize', function () {
    setTimeout(reference_to_function, 100);
  });
});
于 2019-10-01T23:54:25.680 回答
1

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

window.onresize = function(){ getHeight(); }
于 2014-05-26T06:38:18.373 回答
1

需要注意的是,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);
    });
});
于 2019-04-06T13:31:38.527 回答
1

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

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

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

于 2019-03-06T20:46:05.757 回答
-1

对于那些只想要innerHeightwindow 对象之后的人来说,orientationchange有一个简单的解决方案。使用window.innerWidth. 活动innerWidth期间是完成后:orientationchangeinnerHeightorientationchange

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

于 2018-07-22T10:10:31.943 回答