angular源码学习笔记----(加载)

angular资源:

angular文档:http://docs.angularjs.org/api

angular官网:http://angularjs.org/

angular源码:https://github.com/angular/angular.js

angular下载:http://code.angularjs.org/

学习版本:

1.2.0-rc.2

流程简述:

angular初始化大致上有2部分:

1.初始化angular框架,模块等

2.解析document

1.读取angular.js脚本,执行angular框架上下文脚本

  
(function(window, document, undefined) {
         ...
       })(window, document);

2.初始化angular框架,配置模块,挂载angular对象

  
publishExternalAPI(angular);

3.使用angular框架,初始化(扫描)document中,相应的节点

  
angularInit(document, bootstrap);

angular源码,加载启动部分:

(function(window, document, undefined) {
   //设置严格模式
   'use strict';

   /*********
     省略代码
    *********/

   //尝试绑定使用jquery对象
   bindJQuery();

   //公布angular扩展api函数(初始化angular环境)  
   publishExternalAPI(angular);

   //document加载完成后,加载angular
   jqLite(document).ready(function() {
      //加载angular入口
      angularInit(document, bootstrap);
   });

})(window, document);

angular源码,初始化angular框架部分

function publishExternalAPI(angular){

  /********************************
  设置angular公共属性,成员
  ********************************/
  extend(angular, {
    'bootstrap': bootstrap,
    'copy': copy,
    'extend': extend,
    'equals': equals,
    'element': jqLite,
    'forEach': forEach,
    'injector': createInjector,
    'noop':noop,
    'bind':bind,
    'toJson': toJson,
    'fromJson': fromJson,
    'identity':identity,
    'isUndefined': isUndefined,
    'isDefined': isDefined,
    'isString': isString,
    'isFunction': isFunction,
    'isObject': isObject,
    'isNumber': isNumber,
    'isElement': isElement,
    'isArray': isArray,
    '$$minErr': minErr,
    'version': version,
    'isDate': isDate,
    'lowercase': lowercase,
    'uppercase': uppercase,
    'callbacks': {counter: 0}
  });

  /********************************
  创建angular默认模块
  ********************************/
  angularModule = setupModuleLoader(window);

  /********************************
  尝试挂载ngLocale模块
  ********************************/
  try {
    angularModule('ngLocale');
  } catch (e) {
    angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
  }

  /********************************
  配置ng模块
  ********************************/
  angularModule('ng', ['ngLocale'], ['$provide',
    function ngModule($provide) {
      $provide.provider('$compile', $CompileProvider).
        directive({
            a: htmlAnchorDirective,
            input: inputDirective,
            textarea: inputDirective,
            form: formDirective,
            script: scriptDirective,
            select: selectDirective,
            style: styleDirective,
            option: optionDirective,
            ngBind: ngBindDirective,
            ngBindHtml: ngBindHtmlDirective,
            ngBindTemplate: ngBindTemplateDirective,
            ngClass: ngClassDirective,
            ngClassEven: ngClassEvenDirective,
            ngClassOdd: ngClassOddDirective,
            ngCsp: ngCspDirective,
            ngCloak: ngCloakDirective,
            ngController: ngControllerDirective,
            ngForm: ngFormDirective,
            ngHide: ngHideDirective,
            ngIf: ngIfDirective,
            ngInclude: ngIncludeDirective,
            ngInit: ngInitDirective,
            ngNonBindable: ngNonBindableDirective,
            ngPluralize: ngPluralizeDirective,
            ngRepeat: ngRepeatDirective,
            ngShow: ngShowDirective,
            ngStyle: ngStyleDirective,
            ngSwitch: ngSwitchDirective,
            ngSwitchWhen: ngSwitchWhenDirective,
            ngSwitchDefault: ngSwitchDefaultDirective,
            ngOptions: ngOptionsDirective,
            ngTransclude: ngTranscludeDirective,
            ngModel: ngModelDirective,
            ngList: ngListDirective,
            ngChange: ngChangeDirective,
            required: requiredDirective,
            ngRequired: requiredDirective,
            ngValue: ngValueDirective
        }).
        directive(ngAttributeAliasDirectives).
        directive(ngEventDirectives);
      $provide.provider({
        $anchorScroll: $AnchorScrollProvider,
        $animate: $AnimateProvider,
        $browser: $BrowserProvider,
        $cacheFactory: $CacheFactoryProvider,
        $controller: $ControllerProvider,
        $document: $DocumentProvider,
        $exceptionHandler: $ExceptionHandlerProvider,
        $filter: $FilterProvider,
        $interpolate: $InterpolateProvider,
        $http: $HttpProvider,
        $httpBackend: $HttpBackendProvider,
        $location: $LocationProvider,
        $log: $LogProvider,
        $parse: $ParseProvider,
        $rootScope: $RootScopeProvider,
        $q: $QProvider,
        $sce: $SceProvider,
        $sceDelegate: $SceDelegateProvider,
        $sniffer: $SnifferProvider,
        $templateCache: $TemplateCacheProvider,
        $timeout: $TimeoutProvider,
        $window: $WindowProvider,
        $$urlUtils: $$UrlUtilsProvider
      });
    }
  ]);
}

angular源码,装载angular及module部分

function setupModuleLoader(window) {

  function ensure(obj, name, factory) {
    return obj[name] || (obj[name] = factory());
  }

    /**********************************
     声明window的angular属性
     声明angular的module属性

     注:angular.module设置为return的module函数
     *********************************/
  return ensure(ensure(window, 'angular', Object), 'module', function() {

    var modules = {};

    /**********************************
     module函数
     *********************************/
    return function module(name, requires, configFn) {
                   /*******.
                   省略代码
                   *******/
    });
  });

}

angular源码,入口(angularInit)部分:

function angularInit(element, bootstrap) {
  //检索加载angular的dom元素列表
  var elements = [element],
      //加载angular的dom元素
      appElement,
      //加载的模块
      module,
      //检索angular加载的关键字
      names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
      //提取angular加载模块的正则表达式
      NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;

  //追加加载angular的dom元素
  function append(element) {
    element && elements.push(element);
  }

  /**********************************************************************
   遍历angular加载的关键字

   检索分为两种方式:
     1.使用document.getElementById,检索id中关键字
     2.使用element.querySelectorAll,参考:http://www.w3.org/TR/selectors-api/]
  **********************************************************************/
  forEach(names, function(name) {
    names[name] = true;
    append(document.getElementById(name));
    name = name.replace(':', '\\:');
    if (element.querySelectorAll) {
      forEach(element.querySelectorAll('.' + name), append);
      forEach(element.querySelectorAll('.' + name + '\\:'), append);
      forEach(element.querySelectorAll('[' + name + ']'), append);
    }
  });

  /**********************************************************************
   解析加载angular的dom元素及module

   解析分为两种方式:
      1.获取element.className,提取元素class属性内容,作为module名
      2.获取names中存在于dom元素上的属性,提取属性内容,作为module
  **********************************************************************/
  forEach(elements, function(element) {
    if (!appElement) {
      var className = ' ' + element.className + ' ';
      var match = NG_APP_CLASS_REGEXP.exec(className);
      if (match) {
        appElement = element;
        module = (match[2] || '').replace(/\s+/g, ',');
      } else {
        forEach(element.attributes, function(attr) {
          if (!appElement && names[attr.name]) {
            appElement = element;
            module = attr.value;
          }
        });
      }
    }
  });
  
  //如果存在需要加载angular的dom元素,调用bootstrap引导加载appElement,module
  if (appElement) {
    bootstrap(appElement, module ? [module] : []);
  }
}

学习膜拜:

1.把javascript写出了oop的范,设计模式,设计原则很好的体现了出来。

2.angular的结构,已经不是为了实现的页面功能,而是成为了一个应用框架。

学习吐槽:

setupModuleLoader的时候,死绑定的属性为'angular',我要copy装b改名字,让我咋弄?

angularInit的时候,为毛最初是elements,最后却用一个element去引导,module也只能是最后一个element上的,并且module只能为单模块名。

相关推荐