PhoneGap源码分析8——cordova

08-09 01:38:35   来源:cnblogs   评论: 点击:

在cordova中,首先是导入cordova channel模块,这就是前一篇分析的,之后就触发在channel创建的onDOMContectLoaded事件,接着为了侦听deviceready、resume、pause等事件而重新定义了DOM规范中window和document
转了一圈,再回到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');才算执行完。

相关热词搜索:PhoneGap

上一篇:PhoneGap源码分析7——cordova/channel 下一篇:PhoneGap源码分析10——cordova/builder
分享到: 收藏