繁体   English   中英

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

[英]Mobile viewport height after orientation change

我将监听器附加到orientationchange事件:

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

我需要在orientationchange之后获取文档的高度。 但是,该事件在轮换完成之前触发。 因此,记录的高度反映了实际方向改变之前的 state。

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

使用调整大小事件

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

不要使用超时

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

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.innerWidthwindow.innerHeight的状态。 noChangeCountToEnd数量的后续迭代未检测到值突变或在noEndTimeout毫秒后(以先发生者为准)时,将触发orientationchangeend事件。

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的实现。

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

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

我使用了一段时间由 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。 希望这对某人有帮助!

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

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

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

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

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

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

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

需要注意的是,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);
    });
});

在 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.matchMediascreen.orientation

你可以试试这个。 这个对我有用。 orientationchange在少数浏览器中已被弃用。 请检查兼容性。

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

正如 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了解更多详情和浏览器支持。

对于在orientationchange更改后只想要 window 对象的innerHeight的人来说,有一个简单的解决方案。 使用window.innerWidth orientationchange事件期间的innerWidthorientationchange完成后的innerHeight

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.angleorientationchange事件的目标角度。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM