更靠谱的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学习笔记之获取当前目录的实现代码
Dec 14 Javascript
jQuery使用removeClass方法删除元素指定Class的方法
Mar 26 Javascript
详解AngularJS中的表单验证(推荐)
Nov 17 Javascript
Vue.js父与子组件之间传参示例
Feb 28 Javascript
AngularJS的Filter的示例详解
Mar 07 Javascript
Vuejs入门教程之Vue生命周期,数据,手动挂载,指令,过滤器
Apr 19 Javascript
vue 子组件向父组件传值方法
Feb 26 Javascript
微信小程序websocket实现聊天功能
Mar 30 Javascript
微信小程序分包加载代码实现方法详解
Sep 23 Javascript
JavaScript 替换所有匹配内容及正则替换方法
Feb 12 Javascript
解决Vue的项目使用Element ui 走马灯无法实现的问题
Aug 03 Javascript
Angular CLI发布路径的配置项浅析
Mar 29 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程序
2006/10/09 PHP
用php+mysql一个名片库程序
2006/10/09 PHP
PHP下载远程文件到本地存储的方法
2015/03/24 PHP
支持中文、字母、数字的PHP验证码
2015/05/04 PHP
PHP Post获取不到非表单数据的问题解决办法
2018/02/27 PHP
PHP Swoole异步MySQL客户端实现方法示例
2019/10/24 PHP
用jquery与css打造个性化的单选框和复选框
2010/10/20 Javascript
js控制表单奇偶行样式的简单方法
2013/07/31 Javascript
jQuery实现可以编辑的表格实例详解【附demo源码下载】
2016/07/09 Javascript
深入理解requestAnimationFrame的动画循环
2016/09/20 Javascript
AngularJS  ng-table插件设置排序
2016/09/21 Javascript
jquery实现简单的瀑布流布局
2016/12/11 Javascript
Bootstrap BootstrapDialog使用详解
2017/02/17 Javascript
nodejs中sleep功能实现暂停几秒的方法
2017/07/12 NodeJs
angular中的cookie读写方法
2017/08/02 Javascript
对vue中v-on绑定自定事件的实例讲解
2018/09/06 Javascript
解决vue同一slot在组件中渲染多次的问题
2018/09/06 Javascript
详解javascript设计模式三:代理模式
2019/03/25 Javascript
layer.open 获取不到表单信息的解决方法
2019/09/26 Javascript
vue.js自定义组件实现v-model双向数据绑定的示例代码
2020/01/08 Javascript
[01:00:17]DOTA2-DPC中国联赛 正赛 SAG vs Dynasty BO3 第二场 1月25日
2021/03/11 DOTA
python编写朴素贝叶斯用于文本分类
2017/12/21 Python
使用Django简单编写一个XSS平台的方法步骤
2019/03/25 Python
Django自带的用户验证系统实现
2020/12/18 Python
英国体育器材进口商店:UK Sport Imports
2017/03/14 全球购物
家得宝官网:The Home Depot(全球最大的家居装饰专业零售商)
2018/12/17 全球购物
德国亚洲食品网上商店:asiafoodland.de
2019/12/28 全球购物
机械设计职业生涯规划书
2013/12/27 职场文书
幼儿园中班开学寄语
2014/04/03 职场文书
2014年“向国旗敬礼”网上签名寄语活动方案
2014/09/27 职场文书
公司授权委托书格式样本
2014/10/01 职场文书
2014年体育部工作总结
2014/11/13 职场文书
2014年社区计生工作总结
2014/11/18 职场文书
专项资金申请报告
2015/05/15 职场文书
幼儿园2016年感恩节活动总结
2016/04/01 职场文书
Python利用Turtle绘制哆啦A梦和小猪佩奇
2022/04/04 Python