更靠谱的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 Event学习第六章 事件的访问
Feb 07 Javascript
基于jQuery的仿flash的广告轮播代码
Nov 04 Javascript
js下关于onmouseout、事件冒泡的问题经验小结
Dec 09 Javascript
html的DOM中Event对象onabort事件用法实例
Jan 21 Javascript
Javascript中的getUTCDay()方法使用详解
Jun 10 Javascript
jQuery实现可高亮显示的二级CSS菜单效果
Sep 01 Javascript
微信小程序 wxapp内容组件 progress详细介绍
Oct 31 Javascript
JS前端加密算法示例
Dec 22 Javascript
浅析webpack 如何优雅的使用tree-shaking(摇树优化)
Aug 16 Javascript
vue-cli 引入、配置axios的方法
May 08 Javascript
JS基于ES6新特性async await进行异步处理操作示例
Feb 02 Javascript
使用Vant完成通知栏Notify的提示操作
Nov 11 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
一个更简单的无限级分类菜单代码
2007/01/16 PHP
php截取字符串函数substr,iconv_substr,mb_substr示例以及优劣分析
2014/06/10 PHP
php+mysqli实现将数据库中一张表信息打印到表格里的方法
2015/01/28 PHP
yii 框架实现按天,月,年,自定义时间段统计数据的方法分析
2020/04/04 PHP
location.href 在IE6中不跳转的解决方法与推荐使用代码
2010/07/08 Javascript
Javascript中正则表达式的全局匹配模式分析
2011/04/26 Javascript
浅析jQuery中常用的元素查找方法总结
2013/07/04 Javascript
jQuery学习笔记之jQuery构建函数的7种方法
2014/06/03 Javascript
jQuery ajax serialize() 方法使用示例
2014/11/02 Javascript
如何让你的Lightbox支持滚轮缩放及Base64图片
2014/12/04 Javascript
javascript实现可键盘控制的抽奖系统
2016/03/10 Javascript
javaScript 事件绑定、事件冒泡、事件捕获和事件执行顺序整理总结
2016/10/10 Javascript
使用Promise链式调用解决多个异步回调的问题
2017/01/15 Javascript
详解VUE的状态控制与延时加载刷新
2017/03/27 Javascript
vue项目tween方法实现返回顶部的示例代码
2018/03/02 Javascript
React和Vue中监听变量变化的方法
2018/11/14 Javascript
jQuery实现鼠标移入显示蒙版效果
2020/01/11 jQuery
vue实现表单未编辑或未保存离开弹窗提示功能
2020/04/08 Javascript
解决vuecli3中img src 的引入问题
2020/08/04 Javascript
Python使用Mechanize模块编写爬虫的要点解析
2016/03/31 Python
教大家玩转Python字符串处理的七种技巧
2017/03/31 Python
Python使用QRCode模块生成二维码实例详解
2017/06/14 Python
python字典操作实例详解
2017/11/16 Python
python tkinter界面居中显示的方法
2018/10/11 Python
对python 多线程中的守护线程与join的用法详解
2019/02/18 Python
Python3爬虫之自动查询天气并实现语音播报
2019/02/21 Python
python并发编程 Process对象的其他属性方法join方法详解
2019/08/20 Python
python 采用paramiko 远程执行命令及报错解决
2019/10/21 Python
使用Python文件读写,自定义分隔符(custom delimiter)
2020/07/05 Python
详解Canvas 跨域脱坑实践
2018/11/07 HTML / CSS
德国高品质男装及配饰商城:Cultizm(Raw Denim原色牛仔裤)
2018/04/16 全球购物
Crabtree & Evelyn欧盟:豪华洗浴、身体和护发
2021/03/09 全球购物
将n个数按输入顺序的逆序排列,用函数实现
2012/11/14 面试题
文明班级申报材料
2014/12/24 职场文书
2015小学五年级班主任工作总结
2015/05/21 职场文书
react中useState使用:如何实现在当前表格直接更改数据
2022/08/05 Javascript