// 监听 orientation changes window.addEventListener("orientationchange", function(event) { // 根据event.orientation|screen.orientation.angle等于0|180、90|-90度来判断横竖屏 }, false);
代码添加上后,就各类兼容性问题。这里兼容性问题出如今两个地方:css
orientationchange
html
event.orientation|screen.orientation.angle
git
以下是orientationchange
事件的兼容性:github
以下是screen.orientation
的兼容性:浏览器
上述方案不行,只能另行他法了。google一下,了解到能够经过resize
配合(window.inner/outerWidth, window.inner/outerHeight)
来实现:dom
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
兼容性:
实现思路:
这里我选择<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); } } } }();
能够再改进一下,在支持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