PhoneGap源碼分析8——cordova


  轉了一圈,再回到cordova這個模塊。

  在cordova中,首先是導入cordova/channel模塊,這就是前一篇分析的,之后就觸發在channel創建的onDOMContectLoaded事件,接着為了偵聽deviceready、resume、pause等事件而重新定義了DOM規范中window和document的addEventListener和removeEventListener,然后再創建cordova這個對象,並作為結果“返回”。

 1 function (require, exports, module) {
 2     
 3 var channel = require('cordova/channel');//導入通道模塊
 4 
 5 /**
 6  * 將通道里面創建的onDOMContectLoaded事件添加至文檔的DOMContentLoaded
 7  * DOMContentLoaded是一個在HTML5中定義的事件,在形成完整的DOM樹之后觸發,不理會圖像、JS文件、CSS文件等是否已下載完畢,類似於jQuery中的ready
 8  */
 9 //在兼容DOM瀏覽器
10 document.addEventListener('DOMContentLoaded', function() {
11     channel.onDOMContentLoaded.fire();                                                                                                                                                                                                                                                                                                                                                                                                                                                             
12 }, false);//第三個參數false表示在事件冒泡階段觸發
13 //在IE瀏覽器
14 if (document.readyState == 'complete' || document.readyState == 'interactive') {
15     channel.onDOMContentLoaded.fire();
16 }
17 
18 //將addEventListener和removeEventListener原函數保留
19 var m_document_addEventListener = document.addEventListener;
20 var m_document_removeEventListener = document.removeEventListener;
21 var m_window_addEventListener = window.addEventListener;
22 var m_window_removeEventListener = window.removeEventListener;
23 
24 var documentEventHandlers = {},//緩存所有的事件處理函數
25     windowEventHandlers = {};
26 
27 //重定義addEventListener和removeEventListener,以方便后面注冊添加pause、resume、deviceReady等事件
28 document.addEventListener = function(evt, handler, capture) {
29 };
30 
31 window.addEventListener = function(evt, handler, capture) {
32 };
33 
34 document.removeEventListener = function(evt, handler, capture) {
35 };
36 
37 window.removeEventListener = function(evt, handler, capture) {
38 };
39 
40 function createEvent(type, data) {
41 }
42 
43 if(typeof window.console === "undefined") {//兼容控制台,如果未定義,就是用簡單對象代替
44 }
45 
46 var cordova = {//創建cordova對象字面量,並作為結果返回
47 };
48 
49 // 注冊pause、resume、deviceReady事件
50 channel.onPause = cordova.addDocumentEventHandler('pause');
51 channel.onResume = cordova.addDocumentEventHandler('resume');
52 channel.onDeviceReady = cordova.addDocumentEventHandler('deviceready');
53 
54 module.exports = cordova;//返回結果
55 
56 }

 從代碼結構上來說,還是比較清晰的,這里補充一點關於IE中的readyState屬性:

(1)uninitialized:未初始化,對象存在但尚未初始化

(2)loading:正在加載,對象正在加載數據

(3)loaded:加載完畢,對象加載數據完成

(4)interactive:交互,可以操作對象了,但還沒有完全加載

(5)complete:完成,對象已經加載完畢。

在第40行有一個createEvent方法:

function createEvent(type, data) {
    var event = document.createEvent('Events');//創建新的Event對象
    event.initEvent(type, false, false);//初始化事件對象,參數:事件類型,事件是否冒泡,是否可以使用preventDefault()方法取消事件
    if (data) {
        for (var i in data) {
            if (data.hasOwnProperty(i)) {//剔除原型中的屬性
                event[i] = data[i];//將傳入的屬性copy至事件對象            
       } } }
return event; }

這里的邏輯就是先創建事件,再使用相應方法初始化,然后復制數據屬性。關於createEvent,我查閱了《Javascript高級程序設計(第3版)》和其它是一些資料,發現描述的有些出入,各位有興趣的朋友可以自己實踐一探究竟,總體來說,這里就是創建一個事件,不影響后續分析。

下面看一下重定義的addEventListener:

//添加事件偵聽
document.addEventListener = function(evt, handler, capture) {
    var e = evt.toLowerCase();//表示事件的名稱
    if (typeof documentEventHandlers[e] != 'undefined') {
        if (evt === 'deviceready') {//設備就緒事件,則只調用一次
            documentEventHandlers[e].subscribeOnce(handler);
        } else {//其它事件,將事件處理函數注入到事件通道中
            documentEventHandlers[e].subscribe(handler);
        }
    } else {//事件的第一個處理程序,調用DOM中原有的添加事件偵聽函數來添加事件偵聽
        m_document_addEventListener.call(document, evt, handler, capture);
    }
};

window.addEventListener = function(evt, handler, capture) {
    var e = evt.toLowerCase();
    if (typeof windowEventHandlers[e] != 'undefined') {
        windowEventHandlers[e].subscribe(handler);
    } else {
        m_window_addEventListener.call(window, evt, handler, capture);
    }
};

移除事件處理程序是其反過程,對於channel.subscribe注入的使用unsubscribe反注入,而通過DOM中addEventListener的添加的使用removeEventListener移除。
再來看看cordova的定義:

 1 var cordova = {
 2     define:define,    // 將內部的define作為cordova中一個屬性開放給調用者
 3     require:require,    // 將內部的require作為cordova中一個屬性開放給調用者
 4     
 5     addWindowEventHandler:function(event, opts) {//添加window事件偵聽,使用內部數組緩存
 6         return (windowEventHandlers[event] = channel.create(event, opts));
 7     },
 8     addDocumentEventHandler:function(event, opts) {//添加document事件偵聽
 9         return (documentEventHandlers[event] = channel.create(event, opts));
10     },
11     removeWindowEventHandler:function(event) {//移除window事件偵聽
12         delete windowEventHandlers[event];
13     },
14     removeDocumentEventHandler:function(event) {//移除document事件偵聽
15         delete documentEventHandlers[event];
16     },
17     
18     //以對象形式返回DOM中原來定義的事件偵聽函數
19     getOriginalHandlers: function() {
20         return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
21         'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
22     },
23     
24     //觸發document事件
25     fireDocumentEvent: function(type, data) {
26         var evt = createEvent(type, data);
27         if (typeof documentEventHandlers[type] != 'undefined') {//已經緩存事件類型
28
setTimeout(function() { 29 documentEventHandlers[type].fire(evt); 30 }, 0);//一個超時0s的調用,也即是當前代碼結束后立即調用
31
} else { 32 document.dispatchEvent(evt);//觸發事件
33
} 34 }, 35 fireWindowEvent: function(type, data) { 36 var evt = createEvent(type,data); 37 if (typeof windowEventHandlers[type] != 'undefined') { 38 setTimeout(function() { 39 windowEventHandlers[type].fire(evt); 40 }, 0); 41 } else { 42 window.dispatchEvent(evt); 43 } 44 }, 45 shuttingDown:false, 46 UsePolling:false, 47 commandQueue:[], 48 commandQueueFlushing:false, 49 50 callbackId: 0, 51 callbacks: {}, 52 callbackStatus: { 53 NO_RESULT: 0, 54 OK: 1, 55 CLASS_NOT_FOUND_EXCEPTION: 2, 56 ILLEGAL_ACCESS_EXCEPTION: 3, 57 INSTANTIATION_EXCEPTION: 4, 58 MALFORMED_URL_EXCEPTION: 5, 59 IO_EXCEPTION: 6, 60 INVALID_ACTION: 7, 61 JSON_EXCEPTION: 8, 62 ERROR: 9 63 }, 64 65 callbackSuccess: function(callbackId, args) {//回調函數 66 }, 67 callbackError: function(callbackId, args) {//發生異常時的回調 68 }, 69 addConstructor: function(func) {//在cordova初始的時候添加處理程序 70 } 71 };

cordova是作為整個結果返回的,主要的方法有用於模塊化的require、define方法、添加和移除window/document上事件偵聽方法、觸發window/document事件方法以及回調等。

  至此,源碼中的5672行的window.cordova = require('cordova');才算執行完。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM