AngularJS权威指南-基本结构
1.AngularJS简介
AngularJS主要用于构建单页面WEB应用,它通过增加开发人员和常见web应用开发任务之间的抽象级别,使构建交互式的现代web应用变得更加简单。
AngularJS通过原生的MVC(model-view-controller)功能增强了HTML。MVC是一个软件架构设计模式,它将表现从用户交互中分离出来,一般的来说模型中包含应用的数据和与数据进行交互方法,视图将数据呈现给用户,而控制器则是二者之间的桥梁。
2.AngularJS中数据绑定第一个应用
AngularJS与传统的web框架不同,它创建实时模板来代替视图,而不是将数据合并进模板之后跟新DOM。
ng-app指令声明所有被其包含的内容都属于AngularJS应用。
视图中的插值会在计算一个或多个变量时被动动态替换,替换结果是字符串中插值被变量的值替代。
自动数据绑定使我们可以将视图理解为模型状态的映射。客户端的数据模型发生变化时,视图就能反映这边变化,并且不需要写任何自定义代码,它就可以工作。
<!DOCTYPE html> <html ng-app> <head lang="en"> <script src="../js/angular.1.4.3.min.js"></script> </head> <body> <div> <h1>Hello {{'World'}}!</h1> </div> </body> </html>
数据模型对象是指$scope对象,$scope对象是一个简单的JS对象,其中的属性可以被视图访问,也可以同控制器进行交互。双向数据绑定,是视图改变了某个值数据模型也会通过脏值检查改变这个值。视图也会重新渲染。
Your name: <input type="text" ng-model="yourname" placeholder="World"> <h1>Hello {{yourname || 'World'}}!</h1>
数据绑定的最佳实践:在视图中通过对象的属性而非对象本身来进行引用绑定。
<div ng-controller="MyController"> <h1>hello {{clock.now}}!</h1> </div> <script> function MyController($scope, $timeout) { $scope.clock = { now: new Date() }; var updateClock = function () { $scope.clock.now = new Date(); }; setInterval(function () { $scope.$apply(updateClock); }, 1000); updateClock(); } </script>
3.模块(module)
模块是定义应用的最佳方式。模块有很多优点:
(1)保持全局命名空间的清洁。
(2)编写测试代码更加容易,并保持其清洁,以便更容易找到互相隔离的功能;
(3)易于在不同应用间复用代码;
(4)使应用能够以任意顺序加载代码的各个部分。
AngularJS声明模块方法:angular.module("ng-name",[])。第一个参数是模块名称,第二个参数是依赖列表(比如bootstrap依赖jquery)依赖的模块需要在本模块加载之前由注入器进行预加载。
AngularJS引用模块方法:angular.module("ng-name")
4.作用域(scope)
作用域(scope)是构成AngularJS应用的核心基础;
应用的作用域和应用的数据模型相关联的,同时作用域也是表达式执行上下文。$scope对象是定义应用业务逻辑,控制器方法和视图属性的地方。
作用域是应用状态的基础,基于动态绑定,我们可以依赖视图在修改数据时立刻更新$scope,也可以依赖$scope在其发生变化时立刻重新渲染视图。
作用域提供了监视数据模型的能力。它允许开发者使用其中的apply机制,将数据模型的变化在整个应用范围内进行通知。
一般的,将应用业务逻辑放在控制器中,将相关的数据都放进控制的作用域中。
ng-app元素会同时绑定$rootScope,所以$rootScope是所有$scope对象的最上层,类似全局作用域。$scope对象在AngularJS充当数据模型,它并不负责处理和操作数据,它只是
视图和HTML之间的桥梁,是视图和控制器之间的胶水。
AngularJS应用的模板常用的一些标记如下:
①指令:将DOM元素增强为可复用的DOM组件的属性或元素
②值绑定:模板语法{{}}可以将表达式绑定在视图上
③过滤器:可以再视图中使用函数,用来进行格式化
④表单控件:用来检测用户输入的控件。
作用域的基本功能:
①提供观察者以监视数据模型的变化。
②可以将数据模型的变化通知整个应用,甚至是系统外的组件。
③可以进行嵌套。隔离业务功能和数据。
④给表达式提供运算时所需的执行环境。
ng-controller指令是在$rootScope中,为这个DOM创建了一个新的$scope对象。
$scope的生命周期
(1)创建:在创建控制器或者指令时,就会创建一个新的作用域,并且在这个新建的控制器函数运行时将作用域传递进去。
(2)链接:当Angular开始运行时,所有的$scope对象,都会附加或者链接到视图中,所有创建$scope对象的函数也会将自身附加到视图中。
(3)更新:当事件循环运行时,它通过执行在$rootScope对象上,每个字作用域都执行自己的脏值检查,如果检测到任意变化,$scope对象会触发指定的回调函数。
(4)销毁:当一个$scope在视图中不在需要时,这个作用域会清理和销毁自己(angular自己会为你处理)。也可以手动调用$scope上的$destory()方法清除。
<div ng-app="myApp1"> <h1>hello {{name}}</h1> <script> angular.module("myApp1", []).run(function ($rootScope) { $rootScope.name = "World" }) </script> </div>
5.控制器
控制器在AngularJS中的作用是增强视图。它可以将与一个独立的视图相关的业务逻辑封装在一个独立的容器中。
AngularJS通过作用域将视图,控制器,指令隔离开来。这样很容易为功能的具体部分编写测试。
独立作用域
h2>独立作用域</h2> <div ng-controller="FirstController"> <h4>The simple</h4> <button ng-click="add(1)" type="button">Add</button> <button ng-click="subtract(1)" type="button">Subtract</button> <h4>Current count:{{counter}}</h4> </div> <hr/> <div ng-controller="MyController2"> <h3>hello {{name}}</h3> </div> <hr/> <div ng-controller="MyController3"> <h3>{{person}}</h3> and Person name: <span>{{person.name}}</span> </div> <script> var app = angular.module("myApp", []); /*独立作用域*/ app.controller("FirstController", function ($scope) { $scope.counter = 0; $scope.add = function (amount) { $scope.counter += amount; } $scope.subtract = function (amount) { $scope.counter -= amount; } }) app.controller("MyController2", function ($scope) { $scope.name = "Zhou" }) app.controller("MyController3", function ($scope) { $scope.person = { name: "ZZZZhou" } }) </script>
继承作用域
所有作用域都通过原型继承而来,也就是说它们都可以访问父级作用域
<h2>继承作用域</h2> <div ng-controller="PerentCtrl"> <div ng-controller="ChildCtrl"> <button ng-click="Add()">Add Name</button> </div> {{person}} </div> <script> var app = angular.module("myApp", []); /*继承作用域*/ app.controller("PerentCtrl", function ($scope) { $scope.person = { greeted: true } }) app.controller("ChildCtrl", function ($scope) { $scope.Add = function () { $scope.person.name = "Ari zyl" } }) </script>
6.表达式
6.1用{{}}符号将一个变量绑定到$scope上的写法本质上就是一个表达式:{{expression}}。当用$watch进行监听时,AngularJS会对表达式或函数进行运算。
表达式和eval(js)非常相似,有几个不同的特性:
①所有表达式都在其所属的作用域内部执行,并有访问本地$scope的权限;
②如果表达式发生了TypeError和ReferenceError并不会抛出异常;
③不允许使用任何流程控制功能(例如if/else);
④可以接受过滤器和过滤器链。
插值字符串:插值允许基于作用域上的某个条件实时更新文本字符串要在字符串模板中做插值操作,需要在你的对象中注入$interpolate服务;
$interpolate服务接受三个参数的函数:
①text:一个包含字符插值标记的字符串(字符串)
②musthaveEXPR:如果将这个参数设置为true,当传入的字符串中不含有表达式会返回null(布尔型)
③trustedcontext:ng会对已经进行过字符插值操作的字符串通过$sec.getTrusted()方法进行严格的上下文转义(字符串)
由于控制器内部设置了一个需要每次变化都重新进行字符插值的自定义输入字段,因此需要$watch来监听数据的变化。
<div ng-controller="Controller2"> <input type="text" ng-model="expr" placeholder="Enter an expression"/> <h4>表达式:{{ parseValue }}</h4> </div> <hr/> <div ng-controller="MyController"> <input type="email" ng-model="to" placeholder="Recipient"/><br/><br/> <textarea ng-model="emailBody" name="" id="" cols="30" rows="10"> <!--you email:{{to}}--> </textarea> <pre>textarea text:{{to}}</pre> </div> <script> var app = angular.module("app2", []); app.controller("Controller2", function ($scope, $parse) { $scope.$watch("expr", function (newVal, oldVal, scope) { if (newVal !== oldVal) { //用该表达式设置parseFun var parseFun = $parse('expr'); //获取经过解析后表达式的值 $scope.parseValue = parseFun(scope); } }) }); app.controller("MyController", function ($scope, $interpolate) { //设置监听 $scope.$watch("emailBody", function (body) { if (body) { var template = $interpolate(body); $scope.previewText = template({to: $scope.to}); } }) }); </script>
6.2如果需要在文本中使用不同于{{}}的符号来标识表达式的开始和结束,可以在$interpolateProvider中配置。
用startSymbol(value)方法修改标识开始的符号。用endSymbol(value)方法修改标识结束的符号。
<div ng-controller="MyController2"> <div id="emailEditor"> <input type="email" ng-model="to" placeholder="Recipient"/> <br/><br/> <textarea name="name" rows="10" cols="30" ng-model="emailBody"> <!--you email:__ to __--> </textarea> </div> <div id="emailPreview"> <pre>textarea text:__ previewText __</pre> </div> </div> <script> angular.module("emailParser", []) .config(['$interpolateProvider', function ($interpolateProvider) { $interpolateProvider.startSymbol("__"); $interpolateProvider.endSymbol("__"); }]) .factory('EmailParser', ['$interpolate', function ($interpolate) { return { parse: function (text, context) { var tempalte = $interpolate(text); return tempalte(context); } }; }]); var app2 = angular.module("app2", ["emailParser"]); app2.controller("MyController2", ['$scope', 'EmailParser', function ($scope, EmailParser) { //设置监听 $scope.$watch("emailBody", function (body) { if (body) { $scope.previewText = EmailParser.parse(body, {to: $scope.to}); } }) }]) </script>