zoukankan      html  css  js  c++  java
  • 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');才算执行完。

    拣尽寒枝不肯栖,寂寞沙洲冷。
    郴江幸自绕郴山,为谁流下潇湘去?
    欲将心事付瑶琴,知音少,弦断有谁听?
    倩何人,唤取红巾翠袖,揾英雄泪!
    零落成泥碾作尘,只有香如故!
  • 相关阅读:
    centos7 启动mongodb时报错ERROR: child process failed, exited with error number 1
    liunxcentos7下 跟目录空间不足docker load镜像报错空间不足
    centos7下初始化硬盘挂载目录
    Jenkins打包出错
    CentOS 7 安装 Percona XtraDB Cluster 5.7
    Etcd集群搭建(证书通信)
    centos7下prometheus+grafana监控
    nginx代理
    装Centos7系统
    Dockerfile常用指令使用案例
  • 原文地址:https://www.cnblogs.com/linjisong/p/2636891.html
Copyright © 2011-2022 走看看