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');才算执行完。

拣尽寒枝不肯栖,寂寞沙洲冷。
郴江幸自绕郴山,为谁流下潇湘去?
欲将心事付瑶琴,知音少,弦断有谁听?
倩何人,唤取红巾翠袖,揾英雄泪!
零落成泥碾作尘,只有香如故!
原文地址:https://www.cnblogs.com/linjisong/p/2636891.html