更靠谱的H5横竖屏检测方法(js代码)


Posted in Javascript onSeptember 13, 2016

前不久,做了一个H5项目,需要在横竖屏变化时,做一些处理。毫无疑问,需要使用orientationchange来监听横竖屏的变化。

方案一:

// 监听 orientation changes
window.addEventListener("orientationchange", function(event) {
 // 根据event.orientation|screen.orientation.angle等于0|180、90|-90度来判断横竖屏
}, false);

代码添加上后,就各种兼容性问题。这里兼容性问题出现在两个地方:

orientationchange

event.orientation|screen.orientation.angle

如下是orientationchange事件的兼容性:

更靠谱的H5横竖屏检测方法(js代码)

如下是screen.orientation的兼容性:

更靠谱的H5横竖屏检测方法(js代码)

方案二:

上述方案不行,只能另行他法了。google一下,了解到可以通过resize配合(window.inner/outerWidth, window.inner/outerHeight)来实现:

window.addEventListener("resize", function(event) {
var orientation=(window.innerWidth > window.innerHeight)? "landscape":"portrait";
if(oritentation === 'portrait'){
// do something ……
} else {
// do something else ……
}
}, false);

这种方案基本满足大部分项目的需求,但是还是有些不足之处:

只要window的size变化,就会不断触发触发resize事件。可以使用setTimeout来优化一下

如果有多个地方需要监听横竖屏,就需要注册多个window.addEventListener("resize", function(event) {……})。能不能通过订阅与发布模式来改进一下,只注册一个resize负责监听横竖屏变化,只要横竖发生变化就发布通知订阅的对象。其他需要监听横竖屏的地方只需订阅一下即可。

关键代码如下:

var resizeCB = function(){
   if(win.innerWidth > win.innerHeight){//初始化判断
    meta.init = 'landscape';
    meta.current = 'landscape';
   } else {
    meta.init = 'portrait';
    meta.current = 'portrait';
   }
   return function(){
    if(win.innerWidth > win.innerHeight){
     if(meta.current !== 'landscape'){
      meta.current = 'landscape';
      event.trigger('__orientationChange__', meta);
     }
    } else {
     if(meta.current !== 'portrait'){
      meta.current = 'portrait';
      event.trigger('__orientationChange__', meta);
     }
    }
   }
  }();

完整代码猛击这里

方案三:

不过个人觉得通过window.innerWidth > window.innerHeight来实现的是一种伪检测,有点不可靠。 可不可以通过浏览器来实现检测?如基于CSS3@media媒体查询来实现。

如下@media兼容性:

更靠谱的H5横竖屏检测方法(js代码)

如上上图所示,移动端浏览器都支持CSS3 media。

实现思路:

创建包含标识横竖屏状态的特定css样式

通过JS向页面中注入CSS代码

resize回调函数中获取横竖屏的状态

这里我选择<html></html>的节点font-family作为检测样式属性。理由如下:

选择<html></html>主要为了避免reflow和repaint

选择font-family样式,主要是因为font-family有如下特性:

  • 优先使用排在前面的字体。
  • 如果找不到该种字体,或者该种字体不包括所要渲染的文字,则使用下一种字体。
  • 如果所列出的字体,都无法满足需要,则让操作系统自行决定使用哪种字体。

这样我们就可以指定特定标识来标识横竖屏的状态,不过需要将指定的标识放置在其他字体的前面,这样就不会引起hmtl字体的变化。

关键代码如下:

// callback
  var resizeCB = function() {
    var hstyle = win.getComputedStyle(html, null),
      ffstr = hstyle['font-family'],
      pstr = "portrait, " + ffstr,
      lstr = "landscape, " + ffstr,
      // 拼接css
      cssstr = '@media (orientation: portrait) { .orientation{font-family:' + pstr + ';} } @media (orientation: landscape) { .orientation{font-family:' + lstr + ';}}';
    // 载入样式    
    loadStyleString(cssstr);
    // 添加类
    html.className = 'orientation' + html.className;
    if (hstyle['font-family'] === pstr) { //初始化判断
      meta.init = 'portrait';
      meta.current = 'portrait';
    } else {
      meta.init = 'landscape';
      meta.current = 'landscape';
    }
    return function() {
      if (hstyle['font-family'] === pstr) {
        if (meta.current !== 'portrait') {
          meta.current = 'portrait';
          event.trigger('__orientationChange__', meta);
        }
      } else {
        if (meta.current !== 'landscape') {
          meta.current = 'landscape';
          event.trigger('__orientationChange__', meta);
        }
      }
    }
  }();

完整代码猛击这里

测试效果

portrait效果:

更靠谱的H5横竖屏检测方法(js代码)

landscape效果:

更靠谱的H5横竖屏检测方法(js代码)

方案四:

可以再改进一下,在支持orientationchange时,就使用原生的orientationchange,不支持则使用方案三。

关键代码如下:

// 是否支持orientationchange事件
var isOrientation = ('orientation' in window && 'onorientationchange' in window);
// callback
var orientationCB = function(e) {
  if (win.orientation === 180 || win.orientation === 0) {
    meta.init = 'portrait';
    meta.current = 'portrait';
  }
  if (win.orientation === 90 || win.orientation === -90) {
    meta.init = 'landscape';
    meta.current = 'landscape';
  }
  return function() {
    if (win.orientation === 180 || win.orientation === 0) {
      meta.current = 'portrait';
    }
    if (win.orientation === 90 || win.orientation === -90) {
      meta.current = 'landscape';
    }
    event.trigger(eventType, meta);
  }
};
var callback = isOrientation ? orientationCB() : (function() {
  resizeCB();
  return function() {
    timer && win.clearTimeout(timer);
    timer = win.setTimeout(resizeCB, 300);
  }
})();
// 监听
win.addEventListener(isOrientation ? eventType : 'resize', callback, false);

完整代码猛击这里

方案五:

目前,上述几种方案都是通过自定制的订阅与发布事件模式来实现的。这里可以基于浏览器的事件机制,来模拟orientationchange。即对orientationchange的不兼容进行修复。

关键代码如下:

var eventType = 'orientationchange';
// 触发原生orientationchange
var fire = function() {
  var e;
  if (document.createEvent) {
    e = document.createEvent('HTMLEvents');
    e.initEvent(eventType, true, false);
    win.dispatchEvent(e);
  } else {
    e = document.createEventObject();
    e.eventType = eventType;
    if (win[eventType]) {
      win[eventType]();
    } else if (win['on' + eventType]) {
      win['on' + eventType]();
    } else {
      win.fireEvent(eventType, e);
    }
  }
}

完整代码猛击这里

通过上述5种方案,自己对移动端横竖屏检测有了更进一步的认识,有些东西只有自己亲身经历过才知道为什么要这么写,自己也把其中缘由记录在文章中,希望对大家有帮助。经过5种方案的演变得到了最终orientationchange-fix,github地址:https://github.com/zhansingsong/orientationchange-fix

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript延时重复执行函数 lLoopRun.js
Jun 29 Javascript
基于Asp.net与Javascript控制的日期控件
May 22 Javascript
JavaScript 中的日期和时间及表示标准介绍
Aug 21 Javascript
js动态添加删除,后台取数据(示例代码)
Nov 25 Javascript
JavaScript禁止页面操作的示例代码
Dec 17 Javascript
jquery和雅虎的yql服务实现天气预报服务示例
Feb 08 Javascript
Javascript中的getUTCHours()方法使用详解
Jun 10 Javascript
学习Javascript面向对象编程之封装
Feb 23 Javascript
深入Vue-Router路由嵌套理解
Aug 13 Javascript
浅谈发布订阅模式与观察者模式
Apr 09 Javascript
el-select 下拉框多选实现全选的实现
Aug 02 Javascript
Layui弹框中数据表格中可双击选择一条数据的实现
May 06 Javascript
jQuery实现的瀑布流加载效果示例
Sep 13 #Javascript
JS实现页面数据无限加载
Sep 13 #Javascript
jQuery实现可展开折叠的导航效果示例
Sep 12 #Javascript
jQuery简单实现列表隐藏和显示效果示例
Sep 12 #Javascript
jQuery实现弹出带遮罩层的居中浮动窗口效果
Sep 12 #Javascript
jQuery实现的无限级下拉菜单功能示例
Sep 12 #Javascript
jQuery实现的图片轮播效果完整示例
Sep 12 #Javascript
You might like
php简单静态页生成过程
2008/03/27 PHP
php 检查电子邮件函数(自写)
2014/01/16 PHP
destoon出现验证码不显示时的紧急处理方法
2014/08/22 PHP
PHP封装分页函数实现文本分页和数字分页
2014/10/23 PHP
PHP 实现的将图片转换为TXT
2015/10/21 PHP
Apache无法自动跳转却显示目录的解决方法
2020/11/30 PHP
PHP7匿名类的用法示例
2019/04/05 PHP
PHP与Web页面的交互示例详解一
2020/08/04 PHP
多次注册事件会导致一个事件被触发多次的解决方法
2013/08/12 Javascript
js 点击页面其他地方关闭弹出层(示例代码)
2013/12/24 Javascript
jquery append()方法与html()方法的区别及使用介绍
2014/08/01 Javascript
5个JavaScript经典面试题
2014/10/13 Javascript
Javascript typeof与instanceof的区别
2016/10/18 Javascript
jQuery中元素选择器(element)简单用法示例
2018/05/14 jQuery
简单了解JS打开url的方法
2020/02/21 Javascript
vue使用swiper实现左右滑动切换图片
2020/10/16 Javascript
python中的实例方法、静态方法、类方法、类变量和实例变量浅析
2014/04/26 Python
Python入门篇之编程习惯与特点
2014/10/17 Python
python结合opencv实现人脸检测与跟踪
2015/06/08 Python
python 定时修改数据库的示例代码
2018/04/08 Python
Python使用selenium实现网页用户名 密码 验证码自动登录功能
2018/05/16 Python
Python3.6实现连接mysql或mariadb的方法分析
2018/05/18 Python
python爬取微信公众号文章
2018/08/31 Python
python如何给字典的键对应的值为字典项的字典赋值
2019/07/05 Python
Python监控服务器实用工具psutil使用解析
2019/12/19 Python
Django中的模型类设计及展示示例详解
2020/05/29 Python
解析python 中/ 和 % 和 //(地板除)
2020/06/28 Python
Pandas对每个分组应用apply函数的实现
2020/12/13 Python
Weekendesk意大利:探索多种引人入胜的周末主题
2016/10/14 全球购物
酒后驾驶检讨书
2014/01/27 职场文书
企业诚信承诺书
2014/05/23 职场文书
我的中国梦口号
2014/06/16 职场文书
大学新生军训自我鉴定
2014/09/18 职场文书
报到证办理个人委托书
2014/10/06 职场文书
Python实现简单的俄罗斯方块游戏
2021/09/25 Python
如何解决flex文本溢出问题小结
2022/07/15 HTML / CSS