angularJS 入门1
来源:互联网 发布:范冰冰洪金宝关系 知乎 编辑:程序博客网 时间:2024/06/06 05:42
要调用自定义指令,HTMl 元素上需要添加自定义指令名。
使用驼峰法来命名一个指令, runoobDirective, 但在使用它时需要以 - 分割, runoob-directive:
留意上方的自定义指令的命名方式与对应在HTML标签中的使用。错误的命名方式可能会造成指令组件无法正常运行。
数据绑定有两个方向:
- 数据 → 界面:我们使用scope对象的$watch()方法监听数据的变化,来更新界面。
- 界面 → 数据:我们在界面的DOM对象上监听变化事件,来更新数据,并通过$apply()方法传播变化。
- $watch()
每个scope对象都维护了一个私有的监听队列,每次当我们在scope上执行一次$watch方法,就相当于 向这个监听队列里塞入一个监听函数。
- $apply()
为了捕捉对数据的修改,AngularJS要求开发者使用scope对象的$apply方法对数据进行修改, $apply方法内部会自动地调用监听队列里的监听函数
在依赖注入的模式下,所有的组件必须通过容器才能相互访问,这导致了在AngularJS中, 你必须通过一个中介才能获得某个组件的实例对象:
- var injector= angular.injector(['ng']);
- injector.invoke(function($http){
- //do sth. with $http
- });
AngularJS的组件之间不可以互相直接调用,一个组件必须通过注入器才 可以调用另一个组件。这样的好处是组件之间相互解耦,对象的整个生命周期的管理 甩给了注入器。
注入器实现了两个重要的功能:
1) 集中存储所有provider的配方
配方其实就是:名称+类构造函数。AngularJS启动时,这些provider首先使用其配方在注入器 内注册。比如,http请求服务组件封装在$httpProvider类内,它通过"$http"这个名字在注入 器内注册。
2) 按需提供功能组件的实例
其他组件,比如一个用户的控制器,如果需要使用http功能,使用"$http"这个名字 向注入器请求,就可以获得一个http服务实例了。
Provider类要求提供一个$get函数(类工厂),injector通过调用该函数, 就可以获得服务组件的实例。
名称和类函数的组合信息,被称为配方。injector中维护一个集中的配方库, 用来按需创建不同的组件。这个配方库,其实就是一个Hash对象,key就是服务名称,value 就是类定义。
在→_→的示例中,我们定义了一个简单的服务类,这个服务类的实例就是一个字符串:“hello,world!”。 我们使用"ezHello"作为其服务名在注入器里注册,并通过注入器将这个实例显示出来。
3.获得注入器对象
要使用AngularJS的功能,必须首先获取注入器。有两种方法取得注入器。
- 创建一个新的注入器
可以使用angular.injector()创建一个新的注入器:
- angular.injector(modules, [strictDi]);
- 获取已经创建的注入器
如果AngularJS框架已经启动,那么可以使用DOM对象的injector()方法获 得已经创建的注入器:
- var element = angular.element(dom_element);
- var injector = element.injector();
通过注入器调用API
注入器有两个方法可供进行API调用:invoke()和get()。
- invoke()
使用注入器的invoke()方法,可以直接调用一个用户自定义的函数体,并通过函数参数 注入所依赖的服务对象,这是AngularJS推荐和惯例的用法:
- angular.injector(['ng'])
- .invoke(function($http){
- //do sth. with $http
- });
- get()
也可以使用注入器的get()方法,获得指定名称的服务实例:
- var my$http = angular.injector(['ng']).get('$http');
- //do sth. with my$http
→_→的示例这次使用了get()方法直接获取一个服务实例:
4. 注入的方式和原理
有两种方法告知注入器需要注入的服务对象:参数名注入和依赖数组注入。
- 参数名注入
AngularJS在执行invoke()函数时,将待注入函数定义转化为字符串,通过 正则表达式检查其参数表,从而发现并注入所所依赖的服务对象:
- //myfunc通过参数表声明这个函数依赖于"$http"服务
- var myfunc = function($http){
- //do sth. with $http
- };
- injector.invoke(myfunc);//myfunc的定义将被转化为字符串进行参数名检查
这样有一个问题,就是当我们对javascript代码进行压缩处理时,$http可能会被 变更成其他名称,这将导致注入失败。
- 依赖数组注入
AngularJS采用依赖项数组的方法解决代码压缩混淆产生的问题。这时传入invoke()的 是一个数组,数组的最后一项是实际要执行的函数,其他项则指明需要向该函数注入 的服务名称。注入器将按照数组中的顺序,依次向函数注入依赖对象。
采用这种方法,待注入函数的参数表的名称就无关紧要了:
- //myfunc依赖于"$http"和"$compile"服务
- var myfunc = ["$http","$compile",function(p1,p2){
- //do sth. with p1($http),p2($compile)
- }];
- injector.invoke(myfunc);
→_→的实例这次采用依赖数组的方法注入了ezHello服务实例,可以改改参数名称 看有没有影响结果?
- ng-app = "ezstuff"
在手动启动引导的场景下,通过bootstrap方法的第二个参数指定需要载入的模块,比如:
- angular.bootstrap(document,["ezstuff"]);
INSIDE:无论自动启动还是手工启动,最终都是调用angular对象上的injector()方法创建了一个 注入器,然后把这个注入器存入了根对象的data里:
- var injector = angular.injector(["ng","ezstuff"]);
- angular.element(document).data("$injector",injector);
如果是自动引导启动,那么ng-app所在的DOM节点对应着根作用域。如果是手工引导启动, 那么在bootstrap方法中指定的第一个参数就对应着根作用域。
无论哪一种情况,一旦$rootScope对象创建成功,AngularJS就将这个对象存储到根节点 的data中,我们可以使用如下的方法查看这个对象:
- angular.element(approot).data("$rootScope");
你可以摆弄一下代码,看看$rootScope到底是什么东西。
编译器$compile是一个AngularJS的内置服务,它负责遍历DOM树来查找匹配指令, 并调用指令的实现代码进行处理。
HTML编译包括3个步骤:
- 匹配指令
$compile遍历DOM树,如果发现有元素匹配了某个指令,那么这个指令将被加入 该DOM元素的指令列表中。一个DOM元素可能匹配多个指令。
- 执行指令的编译函数
当一个DOM元素的所有指令都找齐后,编译器根据指令的优先级/priority指令进行排序。 每个指令的compile函数被依次执行。每个compile执行的结果产生一个link函数,这些 link函数合并成一个复合link函数。
- 执行生成的链接函数
$compile通过执行指令的link函数,将模板和scope链接起来。结果就是一个DOM视图和scope对象模型 之间的动态数据绑定。
为何将编译和连接两个步骤分开?
简单说,当数据模型的变化会导致DOM结构变化时,指令就需要分别定义compile()函数和link函数。 例如,ng-repeat指令需要为数据集合中的每个成员复制DOM元素。将编译和链接过程分开可以有效 地提高性能,因为DOM的复制放在compile()里,仅需要执行一次,但链接则发生在每个生成的DOM元素 上,所以指令的link()函数会执行多次。
指令很少需要compile函数,因为大多数指令考虑的是作用于特定的DOM元素实例,而不是改变DOM 的结构。所以link函数更常用。
笼统地说,指令是DOM元素(例如属性、元素、CSS类等)上的标记符,用来告诉AngularJS的HTML编译器 ($compile服务)将特定的行为绑定到DOM元素,或者改变DOM元素。
指令可以放置在元素名、属性、CSS类名称及备注中。下面是一些等效的触发"ng-bind"指令的写法:
- <span ng-bind="exp"></span>
- <span class="ng-bind: exp;"></span>
- <ng-bind></ng-bind>
- <!-- directive: ng-bind exp -->
指令的实现本质上就是一个类工厂,它返回一个指令定义对象,编译器根据这个指令定义对象进行操作。
指令的规范化
AngularJS在进行匹配检测之前,首先对HTML元素的标签和属性名转化成规范的驼峰式字符串:
- 去除名称前缀的x-和data-
- 以: , - 或 _ 为分割符,将字符串切分成单词,除第一个单词外,其余单词首字母大写
- 重新拼接各单词
例如,下面的写法都等效地匹配ngBind指令:
- <span ng-bind="name"></span> <br/>
- <span ng:bind="name"></span> <br/>
- <span ng_bind="name"></span> <br/>
- <span data-ng-bind="name"></span> <br/>
- <span x-ng-bind="name"></span> <br/>
所以,在前面的课程中,我们在HTML中使用的ez-duang指令,将被规范为ezDuang, 编译器使用这个规范化的名称与注册的指令进行匹配。
- angularJS 入门1
- AngularJS 入门1-基础
- AngularJS入门-(1)
- AngularJS入门篇1-1
- AngularJS入门笔记(1)
- AngularJS入门
- AngularJS入门
- AngularJS 入门
- AngularJS入门
- AngularJs入门
- AngularJS入门
- AngularJS入门
- AngularJs入门
- AngularJS入门
- AngularJs入门
- AngularJS入门
- AngularJS 入门
- angularJS入门
- 一起看代码来玩玩QT之18 database (last QSqlQueryModel 对数据库进行操作(只查不能改)QTableModel 可改,但是QSqlQueryModel也可以添加代理等功)
- Android中MVP设计使用
- 程序员必备算法-最考验逻辑思维能力的十大基础算法
- leetcode:Spiral Matrix 【Java】
- [LeetCode]153 有序数组旋转后的最小值
- angularJS 入门1
- Codeforces--617B--Chocolate(规律)
- C语言中的static 详细分析
- 【历届试题】核桃的数量
- 【设计模式之装饰模式】
- 五、排序算法(选择排序、插入排序、希尔排序)
- Project Euler Problem 91-100
- 使用jstack 发现死锁
- Java提高篇----抽象类与接口