移動手機web頁面轉屏事件兼容解決方案

咱們知道mobile設備上監測轉屏的事件是orientationchange,但這個事件支持得不太好,有些android就不支持orientation事件javascript

zepto.js中擴展了一個 $.support 來檢測是否支持orientationcss

(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 來有效的處轉屏兼容:java

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/982android

思路以下:git

一、 爲頁面添加檢測元素 ,css media query主要仍是在style上起做用,故在頁面建立一個div,做爲media query做用的對象github

$mediaElem = $('<div class="' + cls + '" id="' + id + '"></div>').appendTo('body')

二、 爲檢測元素添加transition樣式及media query樣式 ,當query條件知足時,去動態修改transition做用的屬性,如(width),則可觸發transitionEnd事件,這樣則至關於能夠監測到media query。chrome

$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')

三、 註冊transitionEnd事件 ,在檢測元素上註冊transitionEnd事件數組

$mediaElem.on(transitionEnd, function() {
    ret.matches = $mediaElem.width() === 1;
    $.each(listeners, function (i,fn) {
        $.isFunction(fn) && fn.call(ret, ret);
    });
});

四、封裝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;
    }
};

 

完整源碼: app

(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');
    });
});
相關文章
相關標籤/搜索