笔记来自
《AngularJS入门与进阶》
《AngularJS深度剖析与最佳实践》
where
AngularJS API
库和扩展
batarang 开发工具
数据绑定
是AngularJS框架在视图(DOM元素)与作用域之间建立的数据同步机制。
DOM <---------> 作用域
ng-app <---------> $rootScope
ng-model <--双向---> 当前作用域下的一个属性
ng-bind <--单向---> 当前作用域下的一个属性,作用域到DOM
ng-controller <-----> 控制器,新作用域$scope
作用域
继承
子作用域继承父作用域的所有属性,使用对象原型继承:
function createChildScopeClass(parent){ function ChildScope(){ this.$$watchers=this.$$nextSibling= this.$$childHead=this.$$childTail=null; this.$$listeners={}; this.$$listenerCount={}; this.$$wacthersCount=0; this.$id=nextUid(); this.$$ChildScope=null; } ChildScope.prototype=parent; return ChildScope; }
$digest循环
- $watch作用域上注册watcher监听数据变化事件
- $digest循环来周期性地检查scope模型中的数据是否发生变化,发生改动就冒泡通知,触发watcher。
- 一轮$digest循环在$rootScope开始,随后会访问所有子作用域中的watcher
- $scope.$apply()可以触发$digest , $scope.$apply()-->$rootScope.$digest()
- AngularJS内置的指令或服务通常不需要我们手动调用$apply()方法触发$digest循环
事件传播
- 事件从子作用域路由到父作用域:$scope.$emit("xxx",data)
- 事件从父作用域广播到所有子作用域:$scope.$broadcast("xxx",data)
使用$on()方法注册事件监听器:$scope.on("xxx",function(event,data){}),其中event包括:name,targetScope,currentScope,stopPropagation(),preventDefault(),defaultPrevented。
ng-app
2个作用:
当AngularJS遇到ng-app指令就会创建一个名为$rootScope的作用域,该作用域为AngularJS应用的根作用域。
ng-controller
根据ng-controller指令制定的控制器名称查找控制器构造方法,然后使用对应的构造方法实例化控制对象,并将控制器依赖的对象注入控制器对象中。
控制器对象实例化时Angular会创建一个新的作用域对象,名称为$scope,然后会把$scope对象注入控制器对象中。
ng-init
初始化作用域
ng-model
只能用在表单元素上。
服务
路由与多视图
$routeProvider
$routeProvider.when(path,//路由路径,和$location.path对应 { //route,配置信息 controller:'string|function 控制器名称或构造方法',controllerAs:'string 控制器标识符名称',template:'string|function 模板',templateUrl:'string 模板文件路径',resolve:Ojbect注入到控制器中的内容 }): $routeProvider.otherwise(params):接收string,用于匹配路由中未定义的URL。
ng-view
ng-view指令定义一个视口,用来加载视图内容
$routeParams
在定义路由是,可以在URL中增加参数,用冒号隔开。为了获取URL中传递的参数,可以在控制器中注入$routeParams服务,通过$routeParam.xxxx可访问URL中传递的xxxx参数。
ng-template
使用<script>标签和ng-template指令定义在模板脚本块: <script type="text/ng-template" >....</script>
$location服务
$location服务是AngularJS中和浏览器地址栏URL相关的一个内置服务,始终和浏览器地址栏URL保持同步状态,浏览器地址栏发生改变时,¥location服务会实时更新。使用$location服务可以获取地址栏URL,或者对地址栏URL进行修改,以达到访问不同路由的效果。
$location相关事件:$locationChnageStart,$locationChnageSuccess
$route相关事件:$routeChangeStart,$routeChangeSuccess,$routeChangeError
ng-include
UI Router框架
UI Router基于AngulerJS,用于编写单页面的路由框架,支持多视图嵌套和多个命名视图。
$state / $stateProvider
管理状态定义、当前状态和状态转换。包含触发状态转换的事件和回调函数,异步解决目标状态的任何依赖项,更新$location到当前状态。由于状态包含关联的 url,通过$urlRouterProvider生成一个路由规则来执行转换的状态。
ui-view指示器
渲染状态中定义的视图,是状态中定义的视图的一个占位符。
$urlRouter / $urlRouterProvider
管理了一套路由规则列表来处理当$location发生变化时如何跳转。最低级的方式是,规则可以是任意函数,来检查$location,并在处理完成时候返回true。支持正则表达式规则和通过$urlMatcherFactory编译的UrlMatcher对象的 url 占位符规则。
$urlRouterProvider负责监听$location.当$location变化的时候,$urlRouterProvider开始在一个规则的列表中一个个的查找,直到找到匹配的值。$urlRouterProvider用于在后端指定url的状态配置。所有的url被编译成UrlMatcher对象。
$urlMatcherFactory
将 url和占位符编译为UrlMatcher对象。除了$routeProvider支持的占位符语法之外,它还支持扩展语法,允许一个正则表达式指定占位符,并且能够提取命名参数和查询url的一部分。
$templateFactory
通过$http / $templateCache来加载模板,供状态配置中使用。
表单校验
AngularJS框架自动为<form name="">标签标记了ng-pristine ng-valid的样式
为input标签标记ng-pristine ng-untouched ng-valid ng-empty等样式
CSS样式 | 状态属性 | 秒速 |
---|---|---|
ng-valid | $valid | 表单输入合法 |
ng-invalid | $invalide | 表单输入不合法 |
ng-pristine | $pristine | 表单元素未被使用 |
ng-dirty | $dirty | 表单元素被使用 |
ng-touched | $touched | 元素获取焦点 |
ng-untouched | $untouched | 元素失去焦点 |
ng-empty | $empty | 元素内容为空 |
表单元素除了上述状态属性,还有$error对象,校验类型对应的属性保存了校验结果,表单相关校验指令:
校验类型 | 属性或指令 |
---|---|
必填项 | required属性 |
最小长度 | ng-minlength="" |
最大长度 | ng-maxlength="" |
模式匹配 | ng-pattern="" |
电子邮件 | type="email" |
数字 | type="number" |
URL | type="url" |
ng-messages指令定义一组表单验证不合法的提示新,需要使用$error对象
ng-message指令用于定义具体某一条表单输入不合法时的提示信息
ng-messages-include
指令
指令的职责是:
AngularJS框架提供了一组内置的指令。内置指令明显包括那些自定义的HTML元素和属性,如ng-include、ng-controller和ng-click,同时也包括标准的HTML元素,如script、a、select和input。这些指令都是AngularJS核心框架默认提供的。
指令的出现方式:元素,属性,class,注释。
将通用的功能封装成指令。AngularJS模块对象module提供了一个directive()方法来实现自定义指令。
指令编译的生命周期
当AngularJS编译一个HTML模板时,它会遍历DOM树,尝试参照已注册的指令集来匹配每个元素、属性、注释及CSS类。每当匹配一个指令时,AngularJS就会调用该指令的编译函数,该函数会返回一个链接函数。AngularJS会收集所有的链接函数。(编译工作是在作用域创建之前执行的,所以在编译函数中没有任何可用的作用域数据)
一旦所有指令都被编译完成,AngularJS就会创建作用域,然后通过调用每个指令对应的链接函数将指令和作用域连接起来。(在链接阶段,作用域已经被附加到指令上,所以链接函数可以将作用域和DOM绑定起来)
编辑阶段通常做一些优化工作。有可能指令的几乎所有工作都会在链接函数中完成(除了一些高级任务,如访问嵌入函数)。而对于重复指令(例如在ng-repeat上的指令),指令的编译函数只会被调用一次,但链接函数在每次迭代时都会被调用,每次迭代对应的数据也会随之变化。
var $compile=...;//injected into your code var scope=...; var html=' '; //step1: parse HTML into DOM element var template=angular.element(html); //step2: compile the template var linkFn=$compile(template); //step3: link the compiled template with the scope linkFn(scope);
模块化
module
|----config-------routes
|----filter
|----directive
|----provider----factory----service----value
|----controller
- 模块是Service、Directive、Filter、配置信息的集合
- 使用angular.module(...)来创建或者获取模块
- 模块之间可以相互依赖
- 模块可以动态加载
- 切分成小模块便于进希单元测试和集成测试
providers service factory
Service,Factory,Provider,Value,Constant都是AngularJS中的可注入类型
- Service:封装了一些特定业务逻辑的单例对象,只会被加载一次,并且是延迟加载
- Factory:
function factory(name,factoryFn,enforce){ //factoryFn返回对象 return provider(name,{ $get: enforce!==false?enforceReturnValue(name,factoryFn):factoryFn }); } function service(name,constructor){ //constructor是service构造函数 return facotry(name,['$injector',function($injector){ return $injector.instantiate(constructor); }]); }
-
| 对象种类 | 可在配置阶段注入 | 可在运行阶段注入 --- | --- | --- | --- Constant | 常量值 | yes | yes Variable | 变量值 | no | yes Service | 构造函数创建的新对象 | no | yes Factory | 工厂函数返回的新对象 | no | yes Provider | $get工厂函数创建的新对象 | yes |no
filters
过滤器的作用是接收一组输入数据,在数据输出到视图前,按照一定的规则对数据进行处理,然后返回处理后的结果。使用方法:
- 表达式{{}}中使用
- 指令中使用
- 在Controller或Service,Provider等服务中使用
AngularJS提供$filter服务,可以调用所有的过滤器。
依赖注入
$jinjector服务实际上是一个IoC容器,当创建一个新的可注入类型,这个可注入类型就会注册到IoC中,AngularJS通过$jnjector服务队这些可注入类型进行集中管理,这就意味着可以通过$injector服务获取所有的可注入类型。(JS实现DI关键是函数对象的toStirng()返回源码,解析参数调用apply)
此外AngularJS还提供一个全局的injector()方法来获取$injector服务。
templates
AngularJS启动过程
- 浏览器下载HTML/CSS/JS等
- 浏览器开始构建DOM树(Static DOM)
- jQuery初始化:document挂上DOMContentLoaded事件,并注册一个回调函数
- AngularJS初始化: AngularJS及其子模块(module),按照引入顺序开始它们的初始化过程
4.1 按名字创建一个模块,所谓模块就是一个对象,它是其他Angular对象的注册表;
4.2 在这个模块中注册各种AngularJS对象,如controller,Service,Directive等。这些元素注册后,就会形成一个由名字和回调函数组成的对照表。但是这些回调函数现在还不会开始执行。在这个模块中注册的“config回调函数”,它将在模块刚刚被初始化时执行。在这个模块中注册“run回调函数”,它将在模块初始化完毕时执行。 - jQuery启动:触发DOMContentLoader事件,执行注册的回调函数
- AngularJS启动:查找ng-app指令节点,执行angular.bootstrap(element,moduleName)
- 加载子模块:即初始化子模块
7.1 先创建注入器$injector,把它关联到所在的节点。前面注册的一大堆Angular对象,都需要通过注入器才能被其他代码使用。
7.2 对当前节点关联的模块及其依赖的模块进行初始化,即执行之前注册的“config回调函数”。这个阶段,注册的大多数对象都尚未就绪因此不能使用。在config回调函数中能使用的只有注册的常量Contant对象和Provider类。 - 启动子模块:模块加载完毕之后就执行所有的“run回调函数”,在这个阶段,各种AngularJS对象都可以使用,包括各种Service,Factory等。接下来,路由模块会获得控制权,使用$location服务解析当前页面的URL,然后根据这个URL查找相应的“模板/控制器”对,来准备渲染一个页面。
- 渲染页面:路由模块会先创建一个Scope对象,并且加载模板,加载完毕后把它的内容传给$compile对象。$compile会先把它解析成一个静态DOM树,然后逐个扫描这颗DOM树种的指令,通过这些指令把$Scope对象和DOM树关联起来,包括渲染内容的函数和进行事件处理的函数。最后用它替换一个特定指令所在的节点,在ngRoute中时带有ng-view的节点,在angular-ui-router中则是带有ui-view的节点。
- 数据绑定和摘要循环
比对
AngularJS是模型驱动;jQuery是DOM驱动。
绝对不要先设计你的页面,然后用DOM操作改变它:
在以往的jQuery开发中,我们先设计页面DOM结构,然后再利用jQuery来改变DOM结构或者实现动态交互效果。由于jQuery是为DOM驱动设计的,所以对于拥有复杂交互逻辑的项目,JS代码会变得越来越臃肿,让交互逻辑分散到各处。
而AngularJS是MVVM的,再AngularJS开发中,我们要始终再脑子里挂着Model的弦。不能老想着“我有xxx这个DOM,我要让它做xxx变化”,而应该先思考我们拥有或需要怎样的model数据,然后设计我们的交互数据和交互逻辑,最后才能实现视图,并用$scope来粘合它们。
UI-Router
State base routing for client-side web apps
原文链接:https://www.f2er.com/angularjs/145455.html