【问题标题】:javascript max viewport height after orientation change Android & iOS方向更改后的javascript最大视口高度Android和iOS
【发布时间】:2012-09-20 12:48:29
【问题描述】:

目标:

找到设备的最大视口高度,包括address bar 的空间,以便我们可以动态调整最小主体的大小并将我们的内容向上推。

问题:

移动浏览器以不同方式处理方向状态,并以不同方式在方向变化时更新 DOM 属性。

Detect rotation of Android phone in the browser with JavaScript

对于 Android 手机,screen.widthscreen.height 也会随着设备的旋转而更新。

|==============================================================================|
|     Device     | Events Fired      | orientation | innerWidth | screen.width |
|==============================================================================|
| iPad 2         | resize            | 0           | 1024       | 768          |
| (to landscape) | orientationchange | 90          | 1024       | 768          |
|----------------+-------------------+-------------+------------+--------------|
| iPad 2         | resize            | 90          | 768        | 768          |
| (to portrait)  | orientationchange | 0           | 768        | 768          |
|----------------+-------------------+-------------+------------+--------------|
| iPhone 4       | resize            | 0           | 480        | 320          |
| (to landscape) | orientationchange | 90          | 480        | 320          |
|----------------+-------------------+-------------+------------+--------------|
| iPhone 4       | resize            | 90          | 320        | 320          |
| (to portrait)  | orientationchange | 0           | 320        | 320          |
|----------------+-------------------+-------------+------------+--------------|
| Droid phone    | orientationchange | 90          | 320        | 320          |
| (to landscape) | resize            | 90          | 569        | 569          |
|----------------+-------------------+-------------+------------+--------------|
| Droid phone    | orientationchange | 0           | 569        | 569          |
| (to portrait)  | resize            | 0           | 320        | 320          |

因此,很明显要找到最大视口高度,无论方向如何,使用单个函数返回设备的最大高度在一系列设备上永远不会保持不变。

我发现的其他不能让这两个发挥得很好的问题:

  • window.devicePixelRatio 属性可能返回不一致的高度 除以window.outerHeight时。
  • 需要使用延迟 window.setTimeout(function() {}, time) 来让 DOM 元素在方向更改后有机会更新。
  • window.outerHeight 不会更新 iOS 设备的方向更改。使用 screen.availHeight 作为后备,将底部导航栏作为总高度。
  • 使用#header#content#footer 结构会强制您动态重新计算#content{min-height},以便在body 动态更新时将#footer 向下推。

解决方案:

我们先来看看DIV结构:

<style>
#header,#content,#footer{width:100%;}
</style>

<body>
<div id="header"></div>
<div id="content"></div>
<div id="footer"></div>
</body>

我们希望防止设备自行扩展:

<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />

我们需要帮助才能返回最大视口高度并隐藏 iOS 的地址栏:

<script src="iOS.js" type="text/javascript"></script>

http://iosjs.com/

然后检测设备是否支持方向更改并使用调整大小作为后备:

var iOS = (navigator.userAgent.match(/(iPad|iPhone|iPod)/i) ? true : false);
var android = (navigator.userAgent.match(/Android/i) ? true : false);
var supportsOrientationChange = "onorientationchange" in window;
var orientationEvent = supportsOrientationChange ? "orientationchange" : "resize"; 

野兽的肚子:

function updateOrientation()
{
    var orientation = (window.orientation);

    if(android)
    {
        window.setTimeout(function() {
            window.scrollTo(0,0);
            var size = window.outerHeight/window.devicePixelRatio;
            $('body').css('min-height', size + 'px');
            var headerHeight = $('#header').height();
            var footerHeight = $('#footer').height();
            var contentHeight = size - (headerHeight+footerHeight);
            $('#content').css('min-height', contentHeight + 'px');
            window.scrollTo(0,1);
        }, 200);
    }

    if(iOS)
    {
        window.setTimeout(function(){
            window.scrollTo(0,0);
            var size = iOS_getViewportSize();
            var headerHeight = $('#header').height();
            var footerHeight = $('#footer').height();
            var contentHeight = size.height - (headerHeight+footerHeight);
            $('#content').css('min-height', contentHeight + 'px');
            window.scrollTo(0,1);
        }, 0);
    }
}

为页面加载和方向事件添加事件监听器:

if(iOS)
{
    iOS_addEventListener(window, "load", iOS_handleWindowLoad);
    iOS_addEventListener(window, "orientationchange", iOS_handleOrientationChange);
    iOS_addEventListener(window, "resize", iOS_handleReize);
}
addEventListener("load", function() 
{
    updateOrientation();
}, false);
addEventListener(orientationEvent, function() {
    updateOrientation();
}, false);

证据在布丁中:

iPhone 4 和 4s 纵向和横向


Android 纵向和横向


这里的目标是缩小此解决方案或使其更好。

【问题讨论】:

  • >> 请不要建议媒体查询。为什么不?您可以用来完成此任务的一种(非常hacky)方法是拥有两个不同方向的CSS文件,并在您认为方向改变时使用javascript检查元素宽度。
  • @Christian 高度正在动态计算以支持跨浏览器的液体布局。我需要为几个元素“重新计算”高度。媒体查询被用在可以使用的地方,这不是这些地方之一。
  • 首先,如果你手动计算高度,那么布局不是“液体”。其次,我看到你的问题是计算高度而不是检测变化,这是正确的吗?如果是这样,那么我的第一个怀疑是您需要 outerHeight 属性。
  • @Christian 我不会和你争论你认为我的问题是什么。我告诉你我的构建确实是流动的,但是有些元素正在动态计算,因此父元素包含的那些子元素也需要动态计算。 outerHeight 与问题无关。问题是方向更改事件不会在移动 safari 浏览器中获取高度/宽度 DOM 更改。谢谢你的努力。

标签: javascript android html ios mobile


【解决方案1】:

这是一个简单的解决方案,它将在加载和调整窗口大小时将浏览器的宽度和高度附加到文档正文。

jQuery.event.add(window, "load", resize);
jQuery.event.add(window, "resize", resize);

  function resize() 
    {
      var h = jQuery(window).height();
      var w = jQuery(window).width();
      jQuery("body").css({"width": w, "height": h});
    }

【讨论】:

    【解决方案2】:

    iOS 模拟器中返回的预期值。我目前无法测试 Android。

    var supportsOrientationChange = "onorientationchange" in window;
    var orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";
    
    window.onload = updateOrientation();
    
    window.addEventListener(orientationEvent, function() {
        updateOrientation();
    }, false);
    
    function updateOrientation(){
        switch(window.orientation){
        case 0:
        alert(window.outerHeight); // Returns '356' with browser chrome
        break;
    
        case -90:
        alert('Landscape right');
        break;
    
        case 90:
        alert(window.outerHeight); // Returns '208' w browser chrome
        break;
    
        case 180:
        //alert('Portrait view - upside down');
        break;
        }
        var orientation = (window.orientation);
    }
    

    (注意:此代码不会在浏览器中测试。)

    【讨论】:

    • 这是“模拟器”还是模拟器? “模拟器”无法正确复制此问题,因此对此我深表歉意。
    • 这是我的 Mac 自带的“iOS 模拟器”
    • 您的 iOS 模拟器是否调用具有相同硬件限制的移动 Safari?抱歉,模拟器不会像实际设备那样复制这个问题。
    • 是的 - 移动 Safari。它是 Xcode 附带的模拟器,“用于构建 Mac、iPhone 和 iPad 应用程序的完整开发人员工具集,包括 Xcode IDE、Instruments 和 iOS 模拟器”developer.apple.com/technologies/ios
    • 它没有相同的硬件限制,但它确实以与实际设备相同的方式正确响应媒体查询和其他环境变量。
    【解决方案3】:

    您可以尝试使用自调用闭包来自行监控方向的变化。像这样的:

    (function () {
    
        var CurrentHeight;
    
        (function CheckForOrientationChange() {
    
            //var NewHeight = window.screen.availHeight / window.devicePixelRatio;
            //var NewHeight = $(window).height();    
    
            var NewHeight = $('#WidthCheck').width();
    
            if (CurrentHeight && CurrentHeight!== NewHeight ) {
    
                alert(NewHeight); // change here
            }
    
            CurrentHeight = NewHeight;
    
            setTimeout(CheckForOrientationChange, 1000);
    
        })();
    
    })();
    

    只需将其放入文档准备功能中即可。现在它每秒检查一次,但您可以缩短该间隔。 jsfiddle 是here,您可以通过更改浏览器的大小来模拟移动浏览器的更改来对其进行测试,然后您可以调整代码来处理您的操作。

    【讨论】:

    • 我知道你在这里做什么。虽然,使用 if (CurrentOrientation &amp;&amp; CurrentOrientation !== NewOrientation) 不允许用户在任何状态下改变方向后拉高。例如,我查看横向我返回 230 像素/我查看纵向我返回 450 像素。您是否可以对此进行修改以支持该修改?
    • 那么这很容易解决:返回 230 和 450 的函数的名称是什么?
    • 我想我的意思是我需要一个函数来在方向改变时返回视口高度。例如,使用 iphone,我希望在横向返回 230 像素,在纵向返回 450 像素。 var h = (window.screen.availHeight/window.devicePixelRatio); alert(h);
    • 查看编辑,刚刚更新为 window.screen.availHeight/window.devicePixelRatio
    • 很抱歉,这不能正确计算 Android 或 iPhone 的最大视口高度。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-07
    • 1970-01-01
    • 1970-01-01
    • 2023-01-26
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多