本系列文章的分析基于AngularJS v1.4.2.

参考资料有:

  • AngularJS API Docs
  • AngularJS Developer Guide
  • AngularJS实战
  • Service vs provider vs factory

1. 整体结构

AngularJS的源码在整体上,与其它很多库和框架一样,是一个自执行函数,其整体结构简化如下:

(function(window, document, undefined) {// define variables and functions// and do some operationsif (window.angular.bootstrap) {console.log('WARNING: Tried to load angular more than once.');return;}bindJQuery();publishExternalAPI(angular);jqLite(document).ready(function() {angularInit(document, bootstrap);});
})(window, document);

整体思路为:

  • 首先是一些全局变量和方法的定义,以及一些其它操作;
  • 通过window.angular.bootstrap判断是否已经加载angular,如果已经加载,则直接退出;
  • 执行bindJQuery(),如果已经加载了jQuery,则AngularJS会使用已经加载的jQuery,否则使用内部实现的JQLite,其相当于是一个简化版的jQuery;
  • 执行publishExternalAPI(angular)来为全局变量angular增加属性和方法,并建立起模块机制,注册核心模块;
  • 在文档加载完成后执行angularInit()

2. bindJQuery

该方法主要是绑定jQuery,简化后的代码如下:

var bindJQueryFired = false;function bindJQuery() {if (bindJQueryFired) {return;}var jqName = jq();jQuery = window.jQuery;if (isDefined(jqName)) {jQuery = jqName === null ? undefined : window[jqName];}if (jQuery && jQuery.fn.on) {jqLite = jQuery;// ... ...} else {jqLite = JQLite;}angular.element = jqLite;bindJQueryFired = true;
}

  • bindJQueryFired相当于是一个标志符,初始值为false。在执行bindJQuery的时候,先判断bindJQueryFired的值,如果其为true,则说明已经执行过jQuery绑定,直接返回;否则执行绑定过程,并将bindJQueryFired的值设置为true;
  • jqName是调用jq()的返回值,jq()的主要作用是遍历文档,找出第一个包含属性ng-jq的节点,然后取其属性值;
  • 变量jQuery取值为window.jQuery,如果加载了jQuery函数库,则其值非空;
  • 在应用了ng-jq指令的情况下,如果jQName的值不为null,则设置变量jQuery的值为window[jqName],否则设置为undefined
  • 如果jQuery变量有效,则使用jQuery变量指定的库;否则使用内置实现的JQLite

总结起来,绑定的jQuery可以的来源有三个:ng-jq指定、引入的jQuery库、内置实现的JQLite,其使用流程为:

  • 如果有ng-jq

    • 如果ng-jq的值不为空,则使用它指定的库
    • 如果ng-jq指定的值为空,则变量jQuery的值为undefined,此时强制使用JQLite,无论是否引入了jQuery库
  • 如果没有ng-jq
    • 如果引入了jQuery库,则使用它
    • 如果没有引入jQuery库,则使用JQLite

3. publishExternalAPI

该方法的代码简化如下:

function publishExternalAPI(angular) {extend(angular, {// ... ...
    });angularModule = setupModuleLoader(window);try {angularModule('ngLocale');} catch (e) {angularModule('ngLocale', []).provider('$locale', $LocaleProvider);}angularModule('ng', ['ngLocale'], ['$provide',function ngModule($provide) {// ... ...
        }]);
}

主要功能为:

  • angular对象进行扩展;
  • 执行setupModuleLoader(window),该方法主要是定义了angular.module方法,用于注册及获取模块;angular.module只有一个参数的时候为获取模块,否则为注册模块;
  • 如果没有注册ngLocal模块,则对其进行注册;
  • 注册ng模块,也就是AngularJS的核心模块。

4. angularInit

该方法的主要作用是启动Angular应用。相关代码为:

var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];function getNgAttribute(element, ngAttr) {var attr, i, ii = ngAttrPrefixes.length;for (i = 0; i < ii; ++i) {attr = ngAttrPrefixes[i] + ngAttr;if (isString(attr = element.getAttribute(attr))) {return attr;}}return null;
}function angularInit(element, bootstrap) {var appElement,module,config = {};// The element `element` has priority over any other elementforEach(ngAttrPrefixes, function(prefix) {var name = prefix + 'app';if (!appElement && element.hasAttribute && element.hasAttribute(name)) {appElement = element;module = element.getAttribute(name);}});forEach(ngAttrPrefixes, function(prefix) {var name = prefix + 'app';var candidate;if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {appElement = candidate;module = candidate.getAttribute(name);}});if (appElement) {config.strictDi = getNgAttribute(appElement, "strict-di") !== null;bootstrap(appElement, module ? [module] : [], config);}
}

需要说明的是,AngularJS支持的属性前缀有多种,包括ng-data-ngng:x-ng-

  • 首先对element进行检测,看它是否有ng-app等属性,如果有则设定appElementmodule
  • 如果element元素没有ng-app等属性,则对其后继元素进行查找,找到第一个有ng-app等属性的元素,从而设定appElementmodule;
  • 如果appElement不为空,即找到了应用的入口元素,则执行bootstrap

需要注意的是,如果有多个元素都有ng-app属性,则只会找到第一个并启动它,而后面的应用则不会自动启动。

5. 应用启动

应用的启动方式主要包括自动启动和手动启动。

(1)自动启动

例如:

<div ng-app="MyModule"><div ng-controller="ctrl">{{ name }}</div>
</div>
<script>var myModule = angular.module('MyModule', []);myModule.controller('ctrl', ['$scope', function($scope) {$scope.name = 'alex';}]);
</script>

在这个例子中,对于最外层的div设置了ng-app属性,因此会自动启动应用。

(2)手动启动

例如:

<div><div ng-controller="ctrl"></div>
</div>
<script>var myModule = angular.module('MyModule', []);myModule.controller('ctrl', ['$scope', function($scope) {$scope.name = 'alex';}]);angular.element(document).ready(function() {angular.bootstrap(document, ['MyModule']);});
</script>

由于没有设置ng-app,因此需要通过angular.bootstrap来手动启动应用。

(3)多个应用的启动

一般情况下,一个页面中只有一个应用,但是一个页面上多个应用也是可以共存的。通过上面对源码的分析,可以知道,只有第一个应用会自动启动,因此其余的应用需要手动来启动,例如:

<div id="app1" ng-app="MyModule1"><div ng-controller="ctrl1"></div>
</div>
<div id="app2" ng-app="MyModule2"><div ng-controller="ctrl2"></div>
</div>
<script>var myModule1 = angular.module('MyModule1', []);myModule1.controller('ctrl1', ['$scope', function($scope) {$scope.name = 'alex';}]);var myModule2 = angular.module('MyModule2', []);myModule2.controller('ctrl2', ['$scope', function($scope) {$scope.greeting = 'hello';}]);angular.element(document).ready(function() {angular.bootstrap(document.getElementById('app2'), ['MyModule2']);});
</script>

 

转载于:https://www.cnblogs.com/folyred/p/4723773.html

AngularJS深入(1)——加载启动相关推荐

  1. AngularJS之手动加载模块app和controller

    AngularJS之手动加载模块app和controller 转载于:https://www.cnblogs.com/baobaodong/p/5157256.html

  2. ant design pro(一)安装、目录结构、项目加载启动【原始、以及idea开发】

    一.概述 1.1.脚手架概念 编程领域中的"脚手架(Scaffolding)"指的是能够快速搭建项目"骨架"的一类工具.例如大多数的React项目都有src,p ...

  3. Linux用户程序的编译链接与加载启动过程

    Linux用户程序的编译链接与加载启动过程 rtoax 2021年3月 1. 程序的编译链接 1.1. 介绍 如果我们打开维基百科的 链接器 页,我们将会看到如下定义: 在计算机科学中,链接器(英文: ...

  4. uboot加载linux内核加载那些内容,几个地址参数及uboot加载启动内核过程的理解

    关于uBoot和Linux内核中几个地址参数及uboot加载启动内核过程的理解 uboot一般使用mkimage工具先制作一个启动映象文件来引导识别内核的,uboot源代码的tools/目录下有mki ...

  5. ZYNQ7000 FSBL加载启动代码详解

    参考资料: https://blog.csdn.net/zhaoxinfan/article/details/54958641 https://blog.csdn.net/asmartkiller/a ...

  6. 详细教你如何部署ICE服务(二)---IceBox加载启动Ice服务

    在上一篇文章中,我使用了自己实现的一个简单容器简单粗暴的启动一个ICE服务,正如上篇文章所总结的那样,这种部署服务的方式存在诸多缺点. 这里我们给出使用IceBox这个框架来开发和部署我们的Ice服务 ...

  7. 在 linux 中加载启动 zynq PL 程序

    目录 环境 使用 BIN 文件生成 附 在 zynq 使用系统时,可在 uboot 与 linux 中加载启动 PL 程序,一直以来用的都是在 uboot 中加载启动,本次试了试在 linux 中启动 ...

  8. AngularJS 无限滚动加载数据控件 ngInfiniteScroll

    为什么80%的码农都做不了架构师?>>>    1.什么是 InfiniteScroll?  无限滚动(Infinite Scroll)也称为自动分页.滚动分页和无限分页.常用在图片 ...

  9. angularjs 路由 异步加载js

    angularjs 异步加载js 有两种方法 第一种  使用$q 和 requireJS 加载 这个问题 首要出现 在 当我 把require 引入 项目中是,希望做到 点击路由时加载相应的页面htm ...

最新文章

  1. 第十七篇:信息抽取Information Extraction
  2. Linux学习(3)-常用命令
  3. oracle11g数据文件路径,oracle11g修改数据文件路径
  4. ​最新综述!基于图神经网络的关系抽取技术进展
  5. ta-lib 里的蜡烛图形态函数源码
  6. Windows下安装jenkins,关闭jenkins,修改jenkins端口号
  7. 组队开发第二周第五次会议
  8. JavaWeb开发Session管理
  9. IntelliJ IDEA后台程序启动
  10. Excel单元格区域快速导出为PDF
  11. VBA每日一练(2),将txt 的部分/全部内容 导入到EXCEL
  12. 【读书笔记】《我的奋斗》罗永浩
  13. Broken Pipe
  14. win7怎么把计算机图标下的箭头掉,告诉你win7如何去除快捷方式小箭头
  15. jsp汽车销售管理系统
  16. 滚动 下拉简单实现分页
  17. linux pclint配置_PC-lint
  18. “链上政务”三管齐下,效率、监管、企业服务成关键词
  19. AlignedReID 源码解析
  20. 00后确实卷,公司新来的卷王,我们这帮老油条真干不过...

热门文章

  1. 【♻️markdown之一次编写,到处使用♻️】markdown文件转word
  2. input的值提交不上
  3. LIVE555再学习 -- testRTSPClient 实例
  4. Binder fuzz安全研究
  5. Android平台类加载流程源码分析
  6. NOIP 2017 总结
  7. linux内存分配缺陷,Linux系统优化-内存错误分析
  8. 数值范围_如何理解PLC对数值运算的定义与处理方式?
  9. 我拿什么融化你,冰冷的电子图书馆?
  10. 启动非java虚拟机方式下运行matlab