web-dev-qa-db-ja.com

方向変更後のモバイルビューポートの高さ

orientationchange イベントにリスナーをアタッチしています:

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

orientationchangeの後のドキュメントの高さを取得する必要があります。ただし、ローテーションが完了する前にイベントがトリガーされます。したがって、記録された高さは、実際の向きが変更される前の状態を反映しています。

方向の変更が完了した後で要素の寸法をキャプチャできるようにするイベントを登録するにはどうすればよいですか?

34
Dan Kanze

向きの変更には、新しい高さと幅を取得するための遅延が必要です。これは80%の確率で機能します。

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

サイズ変更イベントを使用

resizeイベントにはorientationchangeの後に適切な幅と高さが含まれますが、すべてのサイズ変更イベントをリッスンする必要はありません。したがって、方向を変更した後、1回限りのサイズ変更イベントリスナーを追加します。

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

タイムアウトを使用しないでください

タイムアウトは信頼できません-一部のデバイスは、ハードコードされたタイムアウト内で向きの変更をキャプチャできません。これは、予期しない理由、またはデバイスが遅いことが原因である可能性があります。高速なデバイスでは、コードに不必要な遅延が逆に発生します。

25

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

向きの変更の処理はブラウザごとに異なるため、向きの変更イベントの終了をキャプチャする方法はありません。方向の変化の終わりを検出する最も信頼できる方法と最も速い方法のバランスをとるには、レース間隔とタイムアウトが必要です。

リスナーは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 の実装を維持しています。

14
Gajus

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をすぐに取得します。これが誰かを助けることを願っています!

2
burtelli

上記の解決策をいくつか組み合わせて、この問題を解決しました。サイズ変更は4〜5回発生します。 .oneを使用すると、起動が早すぎます。クリストファー・ブルのソリューションに追加された短時間のタイムアウトがうまくいった。

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

私も同じ問題に直面しました。だから私は結局使用しました:

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

これは実験的な機能であり、画面の向きが変更された後、適切なinnerHeightおよびinnerWidthを提供します。

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

ウィンドウのサイズ変更を聞くことが、画面の向きを変更するロジックを実装する最も安全な方法だと思います。

1
sudazzle

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

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度の変更が2つの90度のステップで行われるかどうかはわかりません。開発ツールの助けを借りてブラウザでそれをシミュレートすることはできません。しかし、180、270、または360回転の可能性を完全に回避したい場合は、screen.orientation.angleを使用して角度を計算し、正しい高さと幅を使用することが可能です。イベント中のscreen.orientation.angleは、orientationchangeイベントの目標角度です。

0
coderuby