Angular.js有很多内置的指令和依赖注入,原则上不用引入jQuery库,不用document.getElement一系列函数,尽量避免对DOM的直接操作。AngularJS是通过页面上的变量的值的变化影响DOM的行为和外观、属性等,通过模型去改变页面,而jQuery则强调对DOM的直接操作能力。两者的设计思想完全冲突。下面逐一介绍必须和经常用到的指令。
API:https://docs.angularjs.org/api
开发指南:https://docs.angularjs.org/guide
中文开发指南:https://angular.cn/docs/ts/latest/quickstart.html
学习的总体原则是首先了解别人的东西怎么用,达到预期目的后再去研究别人的东西是怎么帮助我们达到预期目的的。在刚开始讲如何用的时候大家会产生很多为什么是这样的问题,特别是模块的依赖注入问题。某些问题后面会详细说。
编写示例工程过程中有些自己发现的书本没写甚至写错的东西我没有写在文档里,而是写在代码中的注释里或者代码正文中,有的没写注释,只是通过对比实验来体现。比如指令的优先级、指令的作用域等。这些是比较重要的细节,请大家注意看示例工程。
2.2.1.HTML中的表达式
在普通HTML标签中表示AngularJS的变量或者表达式的表示形式是:
{{<变量或者表达式>}}
它实际上是ng-bind指令的一种更方便、更直观的写法。在AngularJS指令中的变量或者表达式绝大部分不需要{{}}。表达式必须有返回值,建议不要只调用一个void类型的函数。即使无意或者有意这样做了也不会引起Angular.js异常。
2.2.2.ng-app
这个指令指示当前HTML页面启用AngularJS。指令可以写在HTML代码的任意位置。指令写的位置决定AnguarJS启作用的范围。AnguarJS只对标记的innerHTML起作用。当然用户可以在控制器里编写操作任意位置HTML的JS代码。一般情况下建议写在HTML标签上。示例工程:T21。
<!DOCTYPE html> <html ng-app> <head lang="en"> <Meta charset="UTF-8"> <script type="text/javascript" src="../vendor/angular.min.js"></script> <title>Hello World!</title> </head> <body> <input ng-model="name" type="text" size="40" placeholder="Input yout name please."> <br/> <h1>Hello,{{name}}</h1> </body> </html>
ng-app还可以带参数。这个以后详细讨论。
2.2.3.模型(Model)与绑定(Binding)
AngularJS是基于MVC思想设计的,它原则上不允许用户直接操作DOM,而是通过数据绑定的方式影响HTML元素的行为和外观。这也是MVC思想的核心表现之一。数据绑定通过ng-model实现,默认双向绑定。关于数据绑定过程、$apply、$watch、$digest等相关知识后面讨论。
示例工程:T22,双向绑定。
HTML代码:
<inputng-model="name" type="text" size="40"placeholder="Input yout name please."> <br/> <inputng-model="name" type="text" size="40"placeholder="Input yout name please.">
JS代码:
无。
2.2.4.控制器(Controller)
DOM元素上的ng-controller声明所有被它包含的元素都属于某个控制器。注入到指定控制器的环境只对它包含的元素有效。angular输出的HTML标签不起作用。
HTML代码:
<!DOCTYPE html> <html lang="en" ng-app="myApp"> <head> <Meta charset="UTF-8"> <title>T22</title> <script type="text/javascript" src="vendor/angular.js"></script> <script type="text/javascript" src="controller.js"></script> </head> <body ng-controller="IndexController"> <p style="{{styleString}}"><span>{{dateString}}</span><span>{{timeString}}</span></p> </body> </html>
JS代码:
class DateTimeHelper { static getDateString(now) { var str = ""; str += (now.getYear() + 1900); str += "-"; str += now.getMonth() < 9 ? "0" + (now.getMonth() + 1).toString() : +(now.getMonth() + 1).toString(); str += "-"; str += now.getDay() < 10 ? "0" + now.getDay().toString() : now.getDay().toString(); return str; } static getTimeString(now) { var str = ""; str += now.getHours() < 10 ? "0" + now.getHours().toString() : now.getHours().toString(); str += ":"; str += now.getMinutes() < 10 ? "0" + now.getMinutes().toString() : now.getMinutes().toString(); str += ":"; str += now.getSeconds() < 10 ? "0" + now.getSeconds().toString() : now.getSeconds().toString(); str += "."; str += now.getMilliseconds() < 10 ? "0" + now.getMilliseconds().toString() : now.getMilliseconds().toString(); return str; } } var module = angular.module("myApp",[]); module.controller("IndexController",function ($scope,$timeout) { updateClock($scope,$timeout); }); function updateClock(scope,timeout) { var now = new Date(); scope.dateString = DateTimeHelper.getDateString(now); scope.timeString = DateTimeHelper.getTimeString(now); var change = (now.getSeconds() % 16).toString(16); scope.styleString = "color:#" + change + "0" + change; scope.redColor = change.toString(16); scope.blueColor = (16 - change).toString(16); console.log("started!"); timeout(()=> { updateClock(scope,timeout); scope.$apply(); console.log("ready!"); },1000); }
2.2.5.数据绑定的最佳实践
由于JavaScript自身的特点,以及它在传递值和引用时的不同处理方式,通常认为,在视图中通过对象的属性而非对象本身来进行引用绑定,是Angular中的最佳实践。如果把这个最佳实践应用到上面时钟的例子中,需要把视图中的代码改写成如示例工程T23所示。
HTML代码:
<!DOCTYPE html> <html lang="en" ng-app="myApp"> <head> <Meta charset="UTF-8"> <script type="text/javascript" src="vendor/angular.js"></script> <script type="text/javascript" src="controllers/index.js"></script> <title>T23</title> </head> <body ng-controller="IndexController"> <p style="{{binding.styleString}}"><span>{{binding.dateString}}</span><span>{{binding.timeString}}</span></p> </body> </html>
控制器代码:
class DateTimeHelper { static getDateString(now) { var str = ""; str += (now.getYear() + 1900); str += "-"; str += now.getMonth() < 9 ? "0" + (now.getMonth() + 1).toString() : +(now.getMonth() + 1).toString(); str += "-"; str += now.getDay() < 10 ? "0" + now.getDay().toString() : now.getDay().toString(); return str; } static getTimeString(now) { var str = ""; str += now.getHours() < 10 ? "0" + now.getHours().toString() : now.getHours().toString(); str += ":"; str += now.getMinutes() < 10 ? "0" + now.getMinutes().toString() : now.getMinutes().toString(); str += ":"; str += now.getSeconds() < 10 ? "0" + now.getSeconds().toString() : now.getSeconds().toString(); str += "."; str += now.getMilliseconds() < 10 ? "0" + now.getMilliseconds().toString() : now.getMilliseconds().toString(); return str; } } var module = angular.module("myApp",$timeout) { var updateClock = function () { var now = new Date(); var change = (now.getSeconds() % 16).toString(16); $scope.binding = { dateString: DateTimeHelper.getDateString(now),timeString: DateTimeHelper.getTimeString(now),styleString: "color:#" + change + "0" + change,redColor: change.toString(16),blueColor: (16 - change).toString(16) }; }; setInterval(()=> { $scope.$apply(updateClock); },1000); updateClock(); });
2.2.6.模块(Module)
模块是定义应用的最主要方式。模块包含了主要的应用代码。一个应用可以包含多个模块,每一个模块都包含了定义具体功能的代码。使用模块能给我们带来许多好处,比如:保持全局命名空间的清洁;编写测试代码更容易,并能保持其清洁,以便更容易找到互相隔离的功能;易于在不同应用间复用代码;使应用能够以任意顺序加载代码的各个部分。
AngularJS允许我们使用angular.module()方法来声明模块,这个方法能够接受三个参数,第一个是模块的名称,第二个是依赖列表,也就是可以被注入到模块中的对象列表,第三个参数是配置回调函数,一般用不上。第二个参数的用法涉及到依赖注入,以后详细说明。第二个参数和第三个参数都是可选的。