更靠谱的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 相关文章推荐
【消息提示组件】,兼容IE6/7&amp;&amp;FF2
Sep 04 Javascript
javascript 对象比较实现代码
Apr 27 Javascript
纯JavaScript实现的完美渐变弹出层效果代码
Apr 02 Javascript
javascript获取设置div的高度和宽度兼容任何浏览器
Sep 22 Javascript
jquery选择器之基本过滤选择器详解
Jan 27 Javascript
通过Jquery的Ajax方法读取将table转换为Json
May 31 Javascript
jquery左边浮动到一定位置时显示返回顶部按钮
Jun 05 Javascript
jQuery循环遍历子节点并获取值的方法
Apr 14 Javascript
jQuery 3.0十大新特性最终版发布
Jul 14 Javascript
webix+springmvc session超时跳转登录页面
Oct 30 Javascript
深入浅出es6模板字符串
Aug 26 Javascript
解决VUE自定义拖拽指令时 onmouseup 与 click事件冲突问题
Jul 24 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编译安装中遇到的两个错误和解决方法
2014/08/20 PHP
php实现的读取CSV文件函数示例
2017/02/07 PHP
php中青蛙跳台阶的问题解决方法
2018/10/14 PHP
PHP创建XML接口示例
2019/07/04 PHP
你可能不再需要JQUERY
2021/03/09 Javascript
javascript里的条件判断
2007/02/27 Javascript
JS实现文字链接感应鼠标淡入淡出改变颜色的方法
2015/02/26 Javascript
jQuery实现新消息在网页标题闪烁提示
2015/06/23 Javascript
关于JavaScript的变量的数据类型的判断方法
2015/08/14 Javascript
解析Node.js基于模块和包的代码部署方式
2016/02/16 Javascript
Bootstrap进度条组件知识详解
2016/05/01 Javascript
JavaScript事件学习小结(一)事件流
2016/06/09 Javascript
浅谈Angularjs link和compile的使用区别
2016/10/21 Javascript
在html中引入外部js文件,并调用带参函数的方法
2016/10/31 Javascript
JavaScript给每一个li节点绑定点击事件的实现方法
2016/12/01 Javascript
js实现网页的两个input标签内的数值加减(示例代码)
2017/08/15 Javascript
JavaScript求一组数的最小公倍数和最大公约数常用算法详解【面向对象,回归迭代和循环】
2018/05/07 Javascript
详解如何写出一个利于扩展的vue路由配置
2019/05/16 Javascript
Javascript Dom元素获取和添加详解
2019/09/24 Javascript
用VsCode编辑TypeScript的实现方法
2020/05/07 Javascript
全面解析js中的原型,原型对象,原型链
2021/01/25 Javascript
python实现给字典添加条目的方法
2014/09/25 Python
Python双向循环链表实现方法分析
2018/07/30 Python
Python解决两个整数相除只得到整数部分的实例
2018/11/10 Python
Python面向对象之类的内置attr属性示例
2018/12/14 Python
对python PLT中的image和skimage处理图片方法详解
2019/01/10 Python
Pycharm Plugins加载失败问题解决方案
2020/11/28 Python
HTML5拖放API实现拖放排序的实例代码
2017/05/11 HTML / CSS
太阳镜仓库,售价20美元或更少:Sunglass Warehouse
2016/09/28 全球购物
欧洲最大的笔和书写专家:The Pen Shop
2017/03/19 全球购物
亚洲颇具影响力的男性在线购物零售商:His
2019/11/24 全球购物
服装创业计划书范文
2014/02/05 职场文书
合作投资意向书
2014/04/01 职场文书
费用申请报告范文
2015/05/15 职场文书
好员工观后感
2015/06/17 职场文书
Python+pyaudio实现音频控制示例详解
2022/07/23 Python