前言

首先,了解 一下ng的一些概念:

  • module 代码的组织单元,其它东西都是定义在具体的模块中的。
  • app 应用业务,需要多个模块的配合完成。
  • service 仅在数据层面实现特定业务功能的代码封装
  • controller 与DOM结构相关联的东西,即是一种业务封装概念,又体现了项目组织的层级结构
  • filter 改变数据的一种机制
  • directive 与DOM结构相关联,特定功能的封装形式

上面的这些概念基本上就是ng的全部。每一部分都可以自由定义,使用时通过各种要素的相互配合来实现我们的业务需求。

模块(module)

每个ng应用都默认加载一个模块“ng”,该组件内部提供了一些常用的功能,我们可以直接使用使用他们,但这些功能可能没法完成我们的需求。因此ng另外还封装了一些其它模块,如ngAnimate、ngResource、ngRoute等,这些模块分别提供了一些各不相同的功能,注入进来我们就可以完全使用他们。我们也可以通过angular.module来创造、注册和加载模块。

一个模块是 一组服务,指令,控制器,过滤函数和配置信息的集合。

angular.module

我们可以通过angular.module(name, [requires], [configFn])创造一个模块。模块名是绑定到模板中ngApp值,requires是需要依赖加载的模块,configFn是requires加载完成之后的初始化工作。返回一个带有其它方法和属性的模块。

  • provider() $provide.provider()的引用
  • factory() $provide.factory()的引用
  • service() $provide.service()的引用
  • value() $provide.value()的引用
  • constant() $provide.constant()的引用
  • decorator() $provide.decorator()的引用
  • animation() 自定义动画指令,$animateProvider.register()的引用
  • filter() 自定义过滤指令,$filterProvider.register()的引用
  • controller() 自定义控制器,$controllerProvider.register()的引用
  • directive() 自定义指令,$compileProvider.directive()的引用
  • config() 配置函数
  • run() 应用初始化
  • name 模块名
  • requires 依赖模块数组

自定义服务$provide

当你想在当前模块的控制器去引用另一模板的控制器功能时,可以自定义一个相关服务,然后在需要该服务的控制器中显示声明依赖该服务,这样就可在多个控制器中使用同一段逻辑代码。

ng提供服务的过程涉及它的依赖注入机制。而provide服务内置一些使用injector注册服务的方法。

(1)provider方法:注册一个服务提供函数。

该函数是一个构造函数,通过内部的$get属性来提供一个服务。

    var fn = function() {
this.$get = function() {
return "china";
};
} var myApp = angular.module('myApp', [], function($provide) {
$provide.provider('test', fn);
}); myApp.controller('myCtrl', function($scope, test) {
console.log(test);
});

上面是一种定义服务的方法,不常用,而且我也没搞懂,汗。。。

(2)factory方法

是provider方法的简写,相当于provider(name, {get:getFn}),直接把一个函数成是一个对象的get()方法,这样就不用显示地定义一个provider方法了。(3)service方法注册一个服务实例,和factory方法功能相似。区别是factory直接传进get方法即可,而service方法传入的是一个构造函数。即service返回的是一个对象,而factory方法 可以是一个数字或字符串。例如ng入门实例中的phonecat程序内部定义的ajax服务使用的就是factory方法,返回请求的json字符串。

phonecatServices.factory('Phone', ['$resource',
function($resource){
return $resource('phones/:phoneId.json', {}, {
query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
});
}]);

(3)value方法

相当于provider方法中的$get属性函数不需要参数且直接返回值的情况。provider方法中的test服务例子可直接简写:

myApp.value('test',"China");

传入值可以是字符串、数字、数组、对象和函数。

(4)constant方法

和value方法功能类似,即给一个服务名绑定一个常量,该常量可以是字符串、数字、数组、对象和函数。区别就是通过constant方法注册的服务能够被注入进module的配置中,而且不能被decorator方法修改。

(5)decorator(name, decorator)方法

中断一个服务的初始化,修改这个服务。参数name是已经定义但需要被修改的服务名。

var myApp = angular.module('myApp', [])
.config(['test', function(test) {
console.log(test.name);
}])
.constant('test',{name:"constant"})
.value('valueTest',{name:'value'})
.decorator('valueTest', function() {
return {
name: 'decoration'
};
})
.controller('myCtrl', ['valueTest', function(valueTest) {
console.log(valueTest.name);
}]);

自定义指令directive

通过前面的学习,我们慢慢发现,ng中的功能都是通过在相应模板中绑定功能的指令来完成。如

<div ng-controller="Controller">
Hello <input ng-model='name'> <hr/>
<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/>
</div>

而ng的指令绑定方式有element names,attributes,comment,class names

<my-dir></my-dir>
<span my-dir="exp"></span>
<!-- directive: my-dir exp -->
<span class="my-dir: exp;"></span>

ng不仅提供了一些简单的指令供我们使用,同时也允许我们自定义指令。通过模块中的directiveAPI可以定义指令,而最简单的定义指令方式是直接返回一个函数:

angular.module('myApp', [])
.directive('myLink', function($interval, dateFilter) {
return function link(scope, element, attrs) {
var format,
timeoutId; function updateTime() {
element.text(dateFilter(new Date(), format));
} scope.$watch(attrs.myLink, function(value) {
format = value;
updateTime();
}); // 注册$destoty事件,防止内存泄露问题
// 当编译的DOM被销毁时触发
element.on('$destroy', function() {
$interval.cancel(timeoutId);
}); // start the UI update process; save the timeoutId for canceling
timeoutId = $interval(function() {
updateTime(); // update DOM
}, 1000);
}
});

指令名必须是驼峰格式的命名,而直接直接返回函数的形式等同于复杂指令定义方式中的返回link函数

angular.module('myApp', [])
.directive('myCurrentTime', function($interval, dateFilter) { function link(scope, element, attrs) {
var format,
timeoutId; function updateTime() {
element.text(dateFilter(new Date(), format));
} scope.$watch(attrs.myCurrentTime, function(value) {
format = value;
updateTime();
}); // 注册$destoty事件,防止内存泄露问题
// 当编译的DOM被销毁时触发
element.on('$destroy', function() {
$interval.cancel(timeoutId);
}); // start the UI update process; save the timeoutId for canceling
timeoutId = $interval(function() {
updateTime(); // update DOM
}, 1000);
} return {
link: link
};
});

即定义指令的复杂形式是返回一个对象,对象含有以下几种可能用到的属性:

  • multiElement
  • priority
  • terminal
  • scope
  • controller
  • require
  • restrict
  • templateNamespace
  • template
  • templateUrl
  • replace(ng2.0中会被移除)
  • transclude
  • compile
  • link

在定义复杂的指令形式之前,我们必须了解一下ng对指令的解析和执行过程:

  • 浏览器将得到的HTML字符串内容解析成DOM结构
  • ng引入,将DOM结构扔给$compile函数处理:
    • $compile遍历DOM匹配指令,将指令添加进匹配DOM元素的指令列表中。一个元素可以匹配多个指令。
    • 关联DOM的多个指令按权重排列
    • 指令指令中的compile函数(可修改DOM结构),返回link函数
    • 得带的所有link函数组成一个列表作为$compile函数的返回
  • 指令link函数(连接模板的scope)

下面是一个复杂指令的定义方式:

myApp.directive('directiveName', function factory(injectables) {
var directiveDefinitionObject = {
priority: 0,
template: '<div></div>', // or // function(tElement, tAttrs) { ... },
// or
// templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
transclude: false,
restrict: 'A',
templateNamespace: 'html',
scope: false,
controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
controllerAs: 'stringIdentifier',
bindToController: false,
require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) { ... },
post: function postLink(scope, iElement, iAttrs, controller) { ... }
}
// or
// return function postLink( ... ) { ... }
},
// or
// link: {
// pre: function preLink(scope, iElement, iAttrs, controller) { ... },
// post: function postLink(scope, iElement, iAttrs, controller) { ... }
// }
// or
// link: function postLink( ... ) { ... }
};
return directiveDefinitionObject;
});
  • multiElement

    当该属性设为true时,HTML编译器会搜集在directive-name-enddirective-name-end之间DOM节点,当作一个集合 作为directive elements使用
  • priority

    设置指令的权重,默认为0.当一个DOM元素匹配多个指令时,根据权重的大小来执行相应的指令。
  • terminal

    设为true时,当前指令是指令集中的最后 一个会被执行的指令。任何权重值小于当前指令权重的指令都不会被指令。
  • scope

    true创建一个新的作用域。{ }创建一个 隔离的scope,可引用相关节点属性:”@attr”引用节点属性,”=attr”把节点属性值引用成scope属性值,“&attr”把节点属性值包装成函数
  • controller

    为指令定义一个controller构造函数,允许指令之间彼此通信。function($scope,$element,$attrs,$transclude){}
  • require

    引用其它指令的控制器作为link函数的第四个参数。跟一个字符串或者字符串数组。

    • (no prefix) 在当前元素内查找控制器
    • ?努力查找或者null
    • ^ 在当前元素和父元素内查找
    • ^^ 在元素的父元素内查找
  • restrict

    决定指令的应用方式,默认EA

    • E 节点名“`
    • A 属性名
    • C 类值
    • M 注释
  • templateNamespace

    模板中的标记。html、svg、math
  • template

    模板内容
  • templateUrl

    模板地址取代模板内容
  • replace

    决定模板内容取代的位置,默认false。true:模板取代指令元素.false:模板取代指令元素的内容。
  • transclude

    true或者element
  • compile

    function compile(tElement,tAttrs, transclude) 装换模板内容。
  • link

    仅当compile属性没有定义时,才会使用。funciton link(scope,iElement,iAttrs,controller,transcludeFn)

    ps:暂时也就只能理解这么多。。。

    可以看官方的一个例子:
<!doctype html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="../js/angular.min.js"></script>
</head>
<body>
<my-tabs>
<my-pane title="Hello">
<h4>Hello1</h4>
<p>Lorem ipsum dolor sit amet</p>
</my-pane>
<my-pane title="World">
<h4>World1</h4>
<em>Mauris elementum elementum enim at suscipit.</em>
<p><a href ng-click="i = i + 1">counter: {{i || 0}}</a></p>
</my-pane>
</my-tabs> <script>
angular.module('myApp', [])
.directive('myTabs', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
controller: function($scope) {
var panes = $scope.panes = []; $scope.select = function(pane) {
angular.forEach(panes, function(pane) {
pane.selected = false;
});
pane.selected = true;
}; this.addPane = function(pane) {
if (panes.length === 0) {
$scope.select(pane);
}
panes.push(pane);
};
},
templateUrl: 'my-tabs.html'
};
})
.directive('myPane', function() {
return {
require: '^myTabs',
restrict: 'E',
transclude: true,
scope: {
title: '@'
},
link: function(scope, element, attrs, tabsCtrl) {
tabsCtrl.addPane(scope);
},
templateUrl: 'my-pane.html'
};
});
</script>
</body>
</html>

my-tabs.html

<div class="tabbable">
<ul class="nav nav-tabs">
<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">
<a href="" ng-click="select(pane)">{{pane.title}}</a>
</li>
</ul>
<div ng-transclude></div>
</div>

my-pane.html

<div class="tabbable">
<ul class="nav nav-tabs">
<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">
<a href="" ng-click="select(pane)">{{pane.title}}</a>
</li>
</ul>
<div ng-transclude></div>
</div>

路由ngRoute

ngRoute模块提供了关于路由方面的一些服务和指令。根据URL中的hash部分发生变化时触发在路由服务中预定义的业务逻辑,例如phonecat应用程序中使用到的路由服务:

phonecatApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: 'PhoneListCtrl'
}).
when('/phones/:phoneId', {
templateUrl: 'partials/phone-detail.html',
controller: 'PhoneDetailCtrl'
}).
otherwise({
redirectTo: '/phones'
});
}]);

运行时会发现这些url匹配的都是url的hash部分,eg: http://localhost:8000/app/#/phones

加载路由

由于ng将路由部分单独作为一个模块服务定义,因此在使用相关路由服务之前,需加载引用:

<script src="../js/angular.min.js"></script>
<script src="../js/angular-route.min.js"></script> angular.module('myapp',['ngRoute']);

使用

要使用路由功能,需要在相应的模块初始化阶段通过引用routeProvider这个服务来定义:(1)routeProvider.when(path, route)

path参数是将要匹配的路径,可以在路径中定义需要获得的参数,例如“/phones/:phoneId”可以匹配”phones/111”,其中phoneId就是变量,即对应变量前使用”:”匹配。

route是对应路由匹配成功后进行的业务处理对象。包含属性:

  • controller 控制器
  • template 模板内容
  • templateUrl 模板路由
  • resolve 可选需要注入进controller中的依赖,是一个对象,对象的key是依赖注入的名,value是string或function
  • redirectTo 重定义到新路由

(2)$routeProvider.otherwise(params)

当以上定义的路由都没有匹配时使用。

(3)ngView

HTML模板指令,当相关路由匹配成功时对应的模板内容加载区域。<div ng-view></div>

(4)routeParams服务路由中的参数对象。键名为路径中定义的参数名。需要提前加载。仅当路由完全改变后对应的routeParams对象才更新。但我们可使用route.current.params来访问新的路由参数。(5)route 控制路由匹配的controllers和views,监控$location.url的变化然后匹配。

  • reload() 重新加载
  • updateParams(newParams) 使用新的路由参数更新当前路由
  • $routeChangesStart 路由改变前的事件
  • $routeChangeSuccess 路由成功改变事件
  • $routeChangeError 路由改变错误事件
  • current 应用当前路由的定义
  • routes 当前路由的默认对象
<div ng-controller="MainController">
Choose:
<a href="Book/Moby">Moby</a> |
<a href="Book/Moby/ch/1">Moby: Ch1</a> |
<a href="Book/Gatsby">Gatsby</a> |
<a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
<a href="Book/Scarlet">Scarlet Letter</a><br/> <div ng-view></div> <hr /> <pre>$location.path() = {{$location.path()}}</pre>
<pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
<pre>$route.current.params = {{$route.current.params}}</pre>
<pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
<pre>$routeParams = {{$routeParams}}</pre>
</div>

另外,$location是ng中默认提供的一个服务:

- absUrl() 当前绝对路径

- url([url]) 更改或获取路径

- protocol() 当前路径协议

- host()

- port()

- path([path])

- search(search,[paramValue])

- hash([hash])

ngResource

ngResource与ngRoute一样,单独的模板,需要提前加载。

ngResource是AJAX服务的一种更高级,抽象的服务,底层仍然调用AJAX服务,该模块是通过$resource提供了和服务端RESTful接口交互支持的服务。

$resource(url, [paramDefaults], [actions], options)

一个创建可以和RESTful服务端交互的resource对象的工厂函数。

  • url 可以含有参数
  • paramDefaults 默认的url参数值,可以在actions里面被重写
  • actions 自定义的方法列表,扩展默认的方法
  • options 用户自定义设置
    • stripTrailingSlashes 默认为true,省略任何计算的URL后面的斜杠。
phonecatServices.factory('Phone', ['$resource',
function($resource){
return $resource('phones/:phoneId.json', {}, {
query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
});
}]);

ng还提供了一些其它的模块和服务,总之ng在真的很强大,它打破了我们以往按照jQuery+CSS+HTML开发动态网站的思维,将我们带入了另一个全新的世界。


参考

http://www.zouyesheng.com/angular.html

http://www.cnblogs.com/lcllao/archive/2012/10/18/2728787.html

angularJS学习笔记(二)的更多相关文章

  1. AngularJS学习笔记二:AngularJS指令

    AngularJS 指令: AngularJS 通过被称为 指令 的新属性来扩展 HTML. AngularJS 指令是扩展的 HTML 属性,带有前缀 ng-. 几个常用 指令: ng-app 指令 ...

  2. AngularJS学习笔记(二)

    一.AngularJS Select(选择框) 1.使用 ng-options 创建选择框 <div ng-app="myApp" ng-controller="m ...

  3. AngularJS 学习笔记二

    AngularJS指令 指令 描述 讲解 ng_app 定义应用程序的根元素. 指令 ng_bind 绑定 HTML 元素到应用程序数据. 简介 ng_click 定义元素被单击时的行为. HTML ...

  4. angularJS学习笔记二

    angularJS四个特性 1.MVC <!doctype html> <html ng-app> <head> <meta charset="ut ...

  5. AngularJS学习笔记(二) 表单验证案例(ng-repeat/filter)

    这一节相对来说需要理解的东西不是太多,记住了那些api就行了. 还是一个案例(同样来自miaov),一个表单验证,先上代码,然后再对对应的内容进行解释. <!DOCTYPE html> & ...

  6. AngularJs学习笔记--Forms

    原版地址:http://code.angularjs.org/1.0.2/docs/guide/forms 控件(input.select.textarea)是用户输入数据的一种方式.Form(表单) ...

  7. AngularJs学习笔记--expression

    原版地址:http://code.angularjs.org/1.0.2/docs/guide/expression 表达式(Expressions)是类Javascript的代码片段,通常放置在绑定 ...

  8. AngularJs学习笔记--directive

    原版地址:http://code.angularjs.org/1.0.2/docs/guide/directive Directive是教HTML玩一些新把戏的途径.在DOM编译期间,directiv ...

  9. AngularJs学习笔记--bootstrap

    AngularJs学习笔记系列第一篇,希望我可以坚持写下去.本文内容主要来自 http://docs.angularjs.org/guide/ 文档的内容,但也加入些许自己的理解与尝试结果. 一.总括 ...

  10. AngularJs学习笔记--html compiler

    原文再续,书接上回...依旧参考http://code.angularjs.org/1.0.2/docs/guide/compiler 一.总括 Angular的HTML compiler允许开发者自 ...

随机推荐

  1. 发布Office 365插件

    在上一篇博客<VisualStudio 2013开发Office插件>开发完成了插件后,需要将插件发布 发布前需要: Azure 应用服务,作为Office插件的发布空间,地址是:http ...

  2. CF 276C Little Girl and Maximum Sum【贪心+差分】

    C. Little Girl and Maximum Sum time limit per test2 seconds memory limit per test256 megabytes input ...

  3. CF 1006B Polycarp's Practice【贪心】

    Polycarp is practicing his problem solving skill. He has a list of n problems with difficulties a1,a ...

  4. (转载)UIKIt力学教程

    转载自:http://www.cocoachina.com/ios/20131226/7614.html 这篇文章还可以在这里找到 英语,   Ray:这篇教程节选自 iOS 7 教程集,它是 iOS ...

  5. 洛谷 P1852 [国家集训队] 跳跳棋

    题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...

  6. 【找规律】Divide by Zero 2017 and Codeforces Round #399 (Div. 1 + Div. 2, combined) B. Code For 1

    观察一下,将整个过程写出来,会发现形成一棵满二叉树,每一层要么全是0,要么全是1. 输出的顺序是其中序遍历. 每一层的序号形成等差数列,就计算一下就可以出来每一层覆盖到的区间的左右端点. 复杂度O(l ...

  7. 【kd-tree】bzoj3290 Theresa与数据结构

    离线所有操作,对所有可能存在的点建立kd-tree,add相当于权值+1,cancel相当于权值-1. 修改操作要记录kd-tree上每个点的fa,从底向上地进行修改. 优化:若一个矩形框的sumv= ...

  8. 【最小割】【Dinic】bzoj3275 Number

    每个点拆点,分别向源/汇连a[i]的边,满足条件的相互连INF的边,答案为sum-maxflow*2. 因为若有几个点不能同时被选,我们要贪心地选择其中和尽量大的部分,这可以由最小割来保证. #inc ...

  9. 排排看(p20)

    public class paixu{public static void main(String[] args){int x=3;if(x>2){System.out.print(" ...

  10. NDK之打印调试信息Log

    第一步:gradle配置ndk ndk { moduleName "Iso8583Lib" ldLibs "log", "z", " ...