我们知道mobile设备上监测转屏的事件是orientationchange,但这个事件支持得不太好,有些android就不支持orientation事件
zepto.js中扩展了一个 $.support 来检测是否支持orientation
(function($) {
/**
* @name $.support
* - ***orientation*** 检测是否支持转屏事件,UC中存在orientaion,但转屏不会触发该事件,故UC属于不支持转屏事件(iOS 4上qq, chrome都有这个现象)
*/
$.support = $.extend($.support || {}, {
orientation: !(br.uc || (parseFloat($.os.version) < 5 && (br.qq || br.chrome))) && !($.os.android && parseFloat($.os.version) > 3) && "orientation" in window && "onorientationchange" in window
});
})(Zepto);
View Code
本文通过Javascript的window.matchMedia方法 和 css media query 来有效的处转屏兼容:
window.matchMedia 和 media (淘宝的响应式就是用的这个)请参考 https://github.com/gmuteam/GMU/wiki/Media-Query%E5%92%8CmatchMedia%E4%BB%8B%E7%BB%8D 、http://www.w3ctech.com/p/982
思路如下:
1、 为页面添加检测元素 ,css media query主要还是在style上起作用,故在页面创建一个div,作为media query作用的对象
$mediaElem = $('<div class="' + cls + '" id="' + id + '"></div>').appendTo('body')
2、 为检测元素添加transition样式及media query样式 ,当query条件满足时,去动态修改transition作用的属性,如(width),则可触发transitionEnd事件,这样则相当于可以监测到media query。
$style = $('<style></style>').append('.' + cls + '{' + cssPrefix + 'transition: width 0.001ms; width: 0; position: absolute; top: -10000px;}\n').appendTo('head');
$style.append('@media ' + query + ' { #' + id + ' { width: 1px; } }\n')
3、 注册transitionEnd事件 ,在检测元素上注册transitionEnd事件
$mediaElem.on(transitionEnd, function() {
ret.matches = $mediaElem.width() === 1;
$.each(listeners, function (i,fn) {
$.isFunction(fn) && fn.call(ret, ret);
});
});
4、封装addListener及removeListener接口 主要记录在闭包中的listeners数组件,添加和删除回调函数即可
ret = {
matches: $mediaElem.width() === 1 ,
media: query,
addListener: function (callback) {
listeners.push(callback);
return this;
},
removeListener: function (callback) {
var index = listeners.indexOf(callback);
~index && listeners.splice(index, 1);
return this;
}
};
完整源码:
(function ($) {
/**
* 定义,对matchMedia方法进行了封装。原理是用css media query及transitionEnd事件来完成的。在页面中插入media query样式及元素,当query条件满足时改变该元素样式,同时这个样式是transition作用的属性,
* 满足条件后即会触发transitionEnd,由此创建MediaQueryList的事件监听。由于transition的duration time为0.001ms,故若直接使用MediaQueryList对象的matches去判断当前是否与query匹配,会有部分延迟,
* 建议注册addListener的方式去监听query的改变。$.matchMedia的详细实现原理及采用该方法实现的转屏统一解决方案详见
* 返回值MediaQueryList对象包含的属性<br />
* - ***matches*** 是否满足query<br />
* - ***query*** 查询的css query,类似\'screen and (orientation: portrait)\'<br />
* - ***addListener*** 添加MediaQueryList对象监听器,接收回调函数,回调参数为MediaQueryList对象<br />
* - ***removeListener*** 移除MediaQueryList对象监听器<br />
* @method $.matchMedia
* @grammar $.matchMedia(query) ? MediaQueryList
* @param {String} query 查询的css query,类似\'screen and (orientation: portrait)\'
* @return {Object} MediaQueryList
* @example
* $.matchMedia('screen and (orientation: portrait)').addListener(fn);
*/
$.matchMedia = (function() {
var mediaId = 0,
cls = 'gmu-media-detect',
transitionEnd = $.fx.transitionEnd,
cssPrefix = $.fx.cssPrefix,
$style = $('<style></style>').append('.' + cls + '{' + cssPrefix + 'transition: width 0.001ms; width: 0; position: absolute; top: -10000px;}\n').appendTo('head');
return function (query) {
var id = cls + mediaId++,
$mediaElem,
listeners = [],
ret;
$style.append('@media ' + query + ' { #' + id + ' { width: 1px; } }\n') ; //原生matchMedia也需要添加对应的@media才能生效
if ('matchMedia' in window) {
return window.matchMedia(query);
}
$mediaElem = $('<div class="' + cls + '" id="' + id + '"></div>')
.appendTo('body')
.on(transitionEnd, function() {
ret.matches = $mediaElem.width() === 1;
$.each(listeners, function (i,fn) {
$.isFunction(fn) && fn.call(ret, ret);
});
});
ret = {
matches: $mediaElem.width() === 1 ,
media: query,
addListener: function (callback) {
listeners.push(callback);
return this;
},
removeListener: function (callback) {
var index = listeners.indexOf(callback);
~index && listeners.splice(index, 1);
return this;
}
};
return ret;
};
}());
})(Zepto);
/**
* @file 扩展转屏事件
* @name ortchange
* @short ortchange
* @desc 扩展转屏事件orientation,解决原生转屏事件的兼容性问题
* @import lib/zeptov1.0.js, lib/zepto.extend.js
*/
$(function () {
/**
* @name ortchange
* @desc 扩展转屏事件orientation,解决原生转屏事件的兼容性问题
* - ***ortchange*** : 当转屏的时候触发,兼容uc和其他不支持orientationchange的设备,利用css media query实现,解决了转屏延时及orientation事件的兼容性问题
* $(window).on('ortchange', function () { //当转屏的时候触发
* console.log('ortchange');
* });
*/
//扩展常用media query
$.mediaQuery = {
ortchange: 'screen and (width: ' + window.innerWidth + 'px)'
};
//通过matchMedia派生转屏事件
$.matchMedia($.mediaQuery.ortchange).addListener(function () {
$(window).trigger('ortchange');
});
});