《AngularJs实战》学习笔记(慕课网)
1. Controller使用过程中的注意点
- 不要试图去复用Controller, 一个控制器一般只负责一小块视图
- 不要在Controller中操作DOM, 这不是控制器的职责. 封装在指令里.
- 不要在Controller中做数据格式化, ng有很好用的表单控件
- 不要在Controller里面做数据过滤操作, ng有$filter服务
- 一般来说, Controller是不会互相调用的, 控制器之间的交互会通过事件进行 ---> 这是强耦合
2.
<html ng-app> <!--这里ng-app告诉浏览器,这里的html元素是AngularJS应用程序的“所有者”--> <div> <input ng-model="greeting.text"/> <!--ng-model把输入域的值绑定到应用程序变量greeting.text--> <p>{{greeting.text}}, Angular</p> <!-- 双大括号{{}}是AngularJS表达式:把数据绑定到HTML,与ng-bind指令异曲同工。-->
<!-- AngularJS将在表达式书写的位置“输出”数据-->
<!--它很像JS表达式,可以包含文字,运算符和变量-->
</div> .... <script src="js/angular-1.3.0.js"></script> <html>
则p标签中的值会随着input里的输入进行改变.
启动后, 会找ng-app中的指令. 找到ng-model后会生成greeting.text数据模型, 这个模型挂载scope根目录下, 这样所有的{{greeting.text}}都可以获得其值
3. AngularJS四大核心特性
- MVC
- 模块化和依赖注入
- 双向数据绑定
- 指令
4. 关于$scope
- Angularjs的MVC是借助于$scope实现的:
- 作用域也是有层次结构的, 如果在内层作用域中没有找到值则会向上去找, 类似JS中的原型查找
- $scope是一个POJO(Plain Old JavaScript Object)
- $scope提供了一些工具方法$watch()/$apply()
- $scope是表达式的执行环境(或者叫作用域)
- $scope是一个树形结构, 与DOM标签平行
- 子$scope对象会继承父$scope上的属性和方法
- 每一个Angular应用只有一个根$scope对象(一般位于ng-app上)
- $scope可以传播事件, 类似DOM事件, 可以向下也可以向上
- $scope不仅是MVC的基础, 也是后面实现双向数据绑定的基础
- 可以用angular.element($0).scope()进行调试
- $scope的生命周期: Creation->Watcher registration->Model mutation->Mutation observation->Scope destruction
5. AngularJS模块化
var helloModule=angular.module('HelloAngular',[]); helloModule.controller('helloNgCtrl', ['$scope', function($scope){ $scope.greeting = { text: 'Hello' }; }]);
一个完整项目结构
[目录]BookStore | [目录]app | | [目录]css | | [目录]framework | | [目录]imgs | | [目录]js.............................存放js文件 | | | app.js.........................作为启动点的js | | | controllers.js | | | directives.js | | | filters.js | | |- services.js | | [目录]tpls...........................放一些模板,即不完整的html文件片段 | | | bookList.html | | |- hello.html | |- index.html..........................应用的html文件 | [目录]node_modules.......................各种基于NodeJS的工具 | | [目录]http-server |- |- package.json........................npm配置项
- ng-app:定义应用程序的根元素
- ng-bind:绑定HTML元素到应用程序数据
- ng-bind-html:绑定HTML元素的innerHTML到应用程序数据,并移除HTML字符串中危险字符
- ng-bind-template:规定使用膜拜替换的文本内容
- ng-blur:规定blur事件的行为
- ng-change:规定在内容改变时要执行的表达式
- ng-checked:规定元素是否被选中
- ......更多参见 AngularJS指令
- AngularJS模块(Module)定义了AngularJS应用
- AngularJS控制器用于控制AngularJS应用
- ng-app指令定义了应用,ng-controller定义了控制器
6. 使用ngRoute进行视图之间的路由
$routeProvider.when('/hello',{ //$routeProvider提供路由, 当访问"hello"时会调用hello.html模板, 控制器HelloCtrl控制视图 templateUrl: 'tpls/hello.html', controller:'HelloCtrl' }).when('/list',{ templateUrl:'tpls/bookList.html', controller:'BookListCtrl' }).otherwise({ redirectTo: '/hello' })
7. ng官方推荐的模块切分方式:
app
|
-----------------------------------------------
| | | | |
controllers directives services routes filters
- 任何一个ng应用都是由控制器, 指令, 路由, 过滤器等有限的模块类型构成的
- 控制器, 指令, 服务, 路由, 过滤器分别放在一个模块里面(可借助于grunt合并)
- 用一个总的app模块作为入口点, 它依赖其他所有模块
1 <!DOCTYPE html> 2 <html ng-app="bookStore"> 3 <!-- ng-app只有一个,相当于main方法 --> 4 <head> 5 <title></title>
<script>.....</script>
6 </head> 7 <body> 8 <div ng-view> 9 10 </div> 11 </body> 12 </html>//controller.js
1 var bookStoreApp = angular.module('bookStoreApp',[ 2 'ngRoute','ngAnimate','bookStoreCtrls','bookStoreFilters', 3 'bookStoreServices','bookStoreDirectives' 4 ]); //依赖注入. 模块之间的依赖的实现. 也可以加载angularjs自带的模块,比如ngAnimate, 记得在html中把script文件引入 5 6 bookStoreApp.config(function($routeProvider){ 7 $routeProvider.when('/hello',{ 8 templateUrl: 'tpls/hello.html', 9 controller:'HelloCtrl' 10 }).when('/list',{ 11 templateUrl:'tpls/bookList.html', 12 controller:'BookListCtrl' 13 }).otherwise({ 14 redirectTo: '/hello' 15 }) 16 });1 //directives.js 2 var bookStoreDirectives = angular.module('bookStoreDirectives', []); 3 4 bookStoreDirectives.directive('bookStoreDirective_1', ['$scope', 5 function($scope){} 6 ]); 7 8 bookStoreDirectives.directive('bookStoreDirective_2', ['$scope', 9 function($scope){} 10 ]);
1 //services.js 2 var bookStoreServices = angular.module('bookStoreServices', []); 3 4 bookStoreServices.service('bookStoreService_1', ['$scope', 5 function($scope){} 6 ]); 7 8 bookStoreServices.service('bookStoreService_2', ['$scope', 9 function($scope){} 10 ]);
8. ng-bind
如第2条所示的例子, 使用{{}}绑定数据时,可能会在页面加载过程中出现{{greeting.text}},使得页面不美观。 一个解决办法就是使用ng-bind
1 <!DOCTYPE html> 2 <html ng-app> 3 <head> 4 <title></title> 5 </head> 6 <body> 7 <div ng-controller="HelloAngular"> 8 <p><span ng-bind="greeting.text"></span>,Angular</p> 9 </div> 10 </body> 11 <script src="js/angular-1.3.0.js"></script> 12 <script src="HelloAngular_MVC.js"></script> 13 </html>
所以,一般在首页加载时使用ng-bind。后面的页面可以使用{{}}来绑定
9. 双向绑定场景
- form表单
1 <!DOCTYPE html> 2 <html ng-app="userInfoModule"> 3 <!-- ng-app指令定义了一个AngularJS应用程序 --> 4 5 <head> 6 <meta charset="utf-8"> 7 <link rel="stylesheet" type="text/css" href="css\bootstrap-3.3.0-dist\dist\css\bootstrap.css"> 8 <script src="js/angular.js"></script> 9 <script src="Form.js"></script> 10 <title></title> 11 </head> 12 13 <body> 14 <div class="panel panel-primary"> 15 <div class="panel-heading"> 16 <div class="panel-title">双向数据绑定</div> 17 </div> 18 <div class="panel-body"> 19 <div class="row"> 20 <div class="col-md-12"> 21 <form class="form-horizontal" role="form" ng-controller="UserInfoCtrl"> 22 <div class="form-group"> 23 <label class="col-md-2 control-label"> 24 邮箱: 25 </label> 26 <div class="col-md-10"> 27 <input class="form-control" type="email" placeholder="推荐使用126邮箱" ng-model="userInfo.email"></input> 28 </div> 29 </div> 30 <div class="form-group"> 31 <label class="col-md-2 control-label"> 32 密码: 33 </label> 34 <div class="col-md-10"> 35 <input class="form-control" type="password" placeholder="只能是数字、字母、下划线" ng-model="userInfo.password"></input> 36 </div> 37 </div> 38 <div class="form-group"> 39 <div class="col-md-offset-2 col-md-10"> 40 <div class="checkbox"> 41 <label> 42 <input type="checkbox" ng-model="userInfo.autoLogin">自动登录 43 </label> 44 </div> 45 </div> 46 </div> 47 <div class="form-group"> 48 <div class="col-md-offset-2 col-md-10"> 49 <button class="btn btn-default" ng-click="getFormData()">获取表单的值</button> 50 <button class="btn btn-default" ng-click="setFormData()">设置表单的值</button> 51 <button class="btn btn-default" ng-click="resetFormData()">重置表单</button> 52 </div> 53 </div> 54 </form> 55 </div> 56 </div> 57 </div> 58 </div> 59 </body> 60 </html>
1 //这里等号右侧括号里第一个参数,模块的名称就是html中主函数入口“ng-app”的名称,即AngularJS应用的根元素 2 //AngularJS模块定义应用 3 var userInfoModule=angular.module('userInfoModule',[]); 4 5 //AngularJS控制器控制应用 6 userInfoModule.controller('UserInfoCtrl',['$scope', function($scope){ 7 $scope.userInfo={ 8 email:"25344528@qq.com", 9 password:"12312313", 10 autoLogin:true 11 }; 12 $scope.getFormData=function(){ 13 console.log($scope.userInfo) 14 }; 15 $scope.setFormData=function(){ 16 $scope.userInfo={ 17 email:'damoqiasss@124.sc', 18 password:"ssss", 19 autoLogin:false 20 } 21 }; 22 $scope.resetFormData = function(){ 23 $scope.userInfo={ 24 email: "123456@a.cc", 25 password:"56", 26 autoLogin:true 27 } 28 } 29 }])
- 例子2:修改样式: 不需要直接操作标签,而是给类绑定不同的值从而使得p标签取得不同的样式属性
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title></title> 5 </head> 6 <body> 7 <!DOCTYPE html> 8 <html ng-app="myCSSModule"> 9 <head> 10 <meta charset="utf-8"> 11 <link rel="stylesheet" type="text/css" href="color.css"> 12 <title></title> 13 </head> 14 15 <body> 16 <div ng-controller="CSSCtrl"> 17 <p class="text-{{color}}">测试CSS样式</p> 18 <button class="btn btn-default" ng-click="setGreen()">绿色</button> 19 <button class="btn btn-default" ng-click="setRed()">红色</button> 20 </div> 21 </body> 22 </html> 23 </body> 24 <script src="js/angular.js"></script> 25 <script src="color.js"></script> 26 </html>
1 var module = angular.module("myCSSModule",[]); 2 3 module.controller('CSSCtrl',['$scope', function($scope){ 4 $scope.setGreen = function(){ 5 $scope.color="green" 6 }; 7 $scope.setRed = function(){ 8 $scope.color="red" 9 } 10 }])
1 .text-red{ 2 color:red; 3 } 4 .text-green{ 5 color:green; 6 }
这里为了避免取不到color值得到text-null这样奇怪的东西,可以使用ng-class:
1 <!DOCTYPE html> 2 <html ng-app="MyCSSModule"> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 <style type="text/css"> 7 .error{ 8 background-color: red; 9 } 10 .warning{ 11 background-color: yellow; 12 } 13 </style> 14 </head> 15 <body> 16 <div ng-controller="HeadController"> 17 <div ng-class='{error: isError, warning: isWarning}'>{{messageText}}</div> 18 <!-- 如果isError是true就使用isError的样式,如果isWarning是true就使用warning的样式。error和warning定义在css中 --> 19 <button ng-click="showError()">Simulate Error</button> 20 <button ng-click="showWarning()">Simulate Warning</button> 21 </div> 22 </body> 23 <script type="text/javascript" src="js/angular.js"></script> 24 <script type="text/javascript"> 25 var module = angular.module("MyCSSModule",[]); 26 27 module.controller("HeadController",["$scope",function($scope){ 28 $scope.isError = false; 29 $scope.isWarning = false; 30 $scope.showError = function(){ 31 $scope.isError = true; 32 $scope.isWarning = false; 33 $scope.messageText = "Error!"; 34 }; 35 $scope.showWarning = function(){ 36 $scope.isError = false; 37 $scope.isWarning = true; 38 $scope.messageText = "Warning!"; 39 }; 40 }]) 41 </script> 42 </html>
- 控制标签的显示与隐藏ng-show. 以及ng-hide与之相反
1 <!DOCTYPE html> 2 <html ng-app="MyCSSModule"> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 <style type="text/css"> 7 .error{ 8 background-color: red; 9 } 10 .warning{ 11 background-color: yellow; 12 } 13 </style> 14 </head> 15 <body> 16 <div ng-controller="HeadController"> 17 <button ng-click="toggleMenu()">Toggle Menu</button> 18 <ul ng-show="menuState.show"> 19 <!-- 使用menuState.show这个模型的值控制下面的li是否显示 --> 20 <li ng-click='stun()'>Stun</li> 21 <li ng-click='disintegrate()'>Disintegrate</li> 22 <li ng-click='erase()'>Erase from history</li> 23 </ul> 24 </div> 25 </body> 26 <script type="text/javascript" src="js/angular.js"></script> 27 <script type="text/javascript"> 28 var module = angular.module("MyCSSModule",[]); 29 30 module.controller("HeadController",["$scope",function($scope){ 31 $scope.menuState={show:false}; 32 $scope.toggleMenu = function(){ 33 $scope.menuState.show = !$scope.menuState.show; 34 }; 35 }]) 36 </script> 37 </html>
- 以及ngAnimate实现页面切换动画等
10. 前端路由
- 使用前端路由的原因:
- AJax请求不会留下History记录
- 用户无法直接通过URL进入应用中的指定页面(保存书签、链接分享给朋友)
- Ajax对SEO是个灾难
- 路由的例子:
// 要导入angular-route.js
1 var bookStoreApp = angular.module('bookStoreApp',[ 2 'ngRoute','ngAnimate','bookStoreCtrls','bookStoreFilters', 3 'bookStoreServices','bookStoreDirectives' 4 ]); //依赖注入. 模块之间的依赖的实现. 也可以加载angularjs自带的模块,比如ngAnimate, 记得在html中把script文件引入 5 6 bookStoreApp.config(function($routeProvider){ 7 $routeProvider.when('/hello',{ 8 templateUrl: 'tpls/hello.html', 9 controller:'HelloCtrl' 10 }).when('/list',{ 11 templateUrl:'tpls/bookList.html', 12 controller:'BookListCtrl' 13 }).otherwise({ 14 redirectTo: '/hello' 15 }) 16 });
这个AngularJS提供的路由机制不能实现路由的深层次嵌套。 可以从github上下载angular-ui-router
<!-- tpl3/index.html --> <div class="container"> <div ui-view="topbar"></div> <div ui-view="main"></div> </div>
var routerApp = angular.module('routerApp',['ui.router']); routerApp.config(function($stateProvider,$urlRouterProvider){ $urlRouterProvider.otherwise('/index'); $stateProvider .state('index',{ url: '/index', views: { '': { templateUrl:'tpls3/index.html' }, 'topbar@index' : { templateUrl: 'tpl3/topbar.html' }, 'main@index': { templateUrl: 'tpl3/home.html' } } }) .state('index.usermng'),{ url: '/usermng', views: { 'main@index': { templateUrl: 'tpls3/usermng.html', controller: function($scope, $state){ $scope.addUserType = function(){ $state.go("index.usermng.addusertype"); } } } } } })
- 前端路由的基本原理
- 哈希#
- HTML5中新的history API
- 路由的核心是给应用定义“状态”
- 使用路由机制会影响到应用的整体编码方式(需要预先定义好状态)
- 考虑兼容性问题与“优雅降级”
11. 指令
- 自定义指令hello:
1 // HelloAngular_Directive.js 2 var myModule = angular.module("MyModule",[]); 3 myModule.directive("hello", function(){ 4 return { 5 restrict: 'AEMC', //四个字母分别表示:属性,元素,注释,类 6 template: '<div>Hi everyone!</div>', 7 replace: true 8 } 9 });
使用hello指令的4种方法:
<!DOCTYPE html> <html ng-app="MyModule"> <head> <meta charset="utf-8"> <title></title> </head> <body> <!-- 法1:使用元素 --> <hello></hello> <!-- 法2:使用 --> <div hello></div> <!-- 法3:使用样式类 --> <div class="hello"></div> <!-- 法4 --> <!-- directive:hello --> <div></div> </body> <script type="text/javascript" src="../test01/js/angular.js"></script> <script type="text/javascript" src="HelloAngular_Directive.js"></script> </html>
- restrict---匹配模式
- 默认使用“A” 属性的方式: <div my-menu=Products></div>
还有E-元素: <my-menu title=Products></my-menu>
C-样式类: <div class=my-menu:Products></div>
M-注释: <!-- directive: my-menu Products --> - 推荐使用元素和属性的方式使用指令
- 当需要创建带有自己的模板的指令时,使用元素名称的方式创建指令
- 当需要为已有的HTML标签增加功能时,使用属性的方式创建指令
- 默认使用“A” 属性的方式: <div my-menu=Products></div>
- template--模板
- template
- templateURl
- templateCache
....myModule.directive("hello"....... ..... template: $templateCache.get("hello.html"), ....
- replace: 元素内部写的内容是否会被替换
- transclude
template: "<div>Hello everyone!<div ng-transclude></div></div> //元素内部的内容替换到ng-transclude里面去
- 指令执行的三个阶段 & compile和link:
- 加载阶段:
- 加载angular.js,找到ng-app指令,确定应用的边界
- 编译阶段
- 遍历DOM,找到所有指令;
- 根据指令代码中的template、replace、transclue转换DOM结构
- 如果存在compile函数则调用
- 链接阶段
- 对每一条指令运行link函数
- link函数一般用来操作DOM,绑定事件监听器
- 关于compile和link:
- compile函数用来对模板自身进行转换, 而link函数负责在模型和视图之间进行动态关联;
- 作用域在链接阶段才会被绑定到编译之后的link函数上
- compile函数仅仅在编译阶段运行一次,而对于指令的每个实例,link函数都会执行一次
- compile可以返回preLink和postLink函数,而link函数只会返回postLink函数
- 如果需要修改DOM结构,应该在postLink中来做这件事情,而如果在preLink中做这件事情会导致错误
- 大多数时候我们只要编写link函数即可
- 加载阶段:
- 使用directive和Controller绑定DOM事件
1 <!-- Directive&Controller.html --> 2 <!DOCTYPE html> 3 <html ng-app="MyModule"> 4 <head> 5 <meta charset="utf-8"> 6 <title></title> 7 </head> 8 <body> 9 <div ng-controller="MyCtrl"> 10 <loader>滑动加载</loader> 11 </div> 12 </body> 13 <script type="text/javascript" src="../test01/js/angular.js"></script> 14 <script type="text/javascript" src="Directive&Controller.js"></script> 15 </html>
//Directive&Controller.js var myModule = angular.module("MyModule",[]); myModule.controller('MyCtrl',['$scope', function($scope){ $scope.loadData = function(){ console.log("加载数据中...."); } }]); myModule.directive("loader", function(){ return { restrict: 'AE', link:function(scope,element,attr){ element.bind("mouseenter",function(){ scope.loadData(); //或者用下面的方法 scope.$apply('loadData()'); }) } }; });
1 <!-- Directive&Controller.html --> 2 <!DOCTYPE html> 3 <html ng-app="MyModule"> 4 <head> 5 <meta charset="utf-8"> 6 <title></title> 7 </head> 8 <body> 9 <div ng-controller="MyCtrl1"> 10 <loader howToLoad="loadData1()">滑动加载</loader> 11 </div> 12 <div ng-controller="MyCtrl2"> 13 <loader howToLoad="loadData2()">滑动加载</loader> 14 </div> 15 </body> 16 <script type="text/javascript" src="../test01/js/angular.js"></script> 17 <script type="text/javascript" src="Directive&Controller.js"></script> 18 </html>
//Directive&Controller.js var myModule = angular.module("MyModule",[]); myModule.controller('MyCtrl1',['$scope', function($scope){ $scope.loadData1 = function(){ console.log("加载数据中....111"); } }]); myModule.controller('MyCtrl2',['$scope', function($scope){ $scope.loadData2 = function(){ console.log("加载数据中....222"); } }]); myModule.directive("loader", function(){ return { restrict: 'AE', link:function(scope,element,attr){ element.bind("mouseenter",function(){ scope.$apply(attr.howtoload); //注意在定义属性中用的的howToLoad的驼峰命名法,在js里只要用小写就可 }) } }; });
- Directive&Directive
<!-- Directive&Directive.html --> <!DOCTYPE html> <html ng-app="MyModule"> <head> <meta charset="utf-8"> <title></title> <link rel="stylesheet" type="text/css" href="..\test01\css\bootstrap-3.3.0-dist\dist\css\bootstrap.css"> </head> <body> <div class="row"> <div class="col-md-3"> <superman strength>动感超人----力量</superman> </div> </div> <div class="row"> <div class="col-md-3"> <superman strength speed>动感超人2----力量+敏捷</superman> </div> </div> <div class="row"> <div class="col-md-3"> <superman strength speed light>动感超人3----力量+敏捷+发光</superman> </div> </div> </body> <script type="text/javascript" src="../test01/js/angular.js"></script> <script type="text/javascript" src="Directive&Directive.js"></script> </html>
//Directive&Directive.js var myModule = angular.module("MyModule",[]); myModule.directive("superman", function(){ return { scope: {}, restrict: 'AE', //指令内部的controller,目的是给指令暴露出public方法给指令外部调用的 controller: function($scope){ $scope.abilities = []; this.addStrength = function(){ $scope.abilities.push("strength"); }; this.addSpeed = function(){ $scope.abilities.push("speed"); }; this.addLight = function(){ $scope.abilities.push("light"); }; }, //如果想定义暴露出的public方法给指令外部调用就使用controller //而link是用于处理指令内部的一些事物,比如给元素绑定事件,改变属性等 link: function(scope,element,attrs){ element.addClass('btn btn-primary'); element.bind('mouseenter',function(){ console.log(scope.abilities); }); } } }); myModule.directive("strength", function(){ return { //require意思是strength指令是依赖superman指令的。link就可以写第四个参数,则link中就可以直接调用supermanCtrl中暴露出来的方法了 require: '^superman', link: function(scope, element, attrs, supermanCtrl){ supermanCtrl.addStrength(); } } }); myModule.directive("speed", function(){ return { require: '^superman', link: function(scope, element, attrs, supermanCtrl){ supermanCtrl.addSpeed(); } } }); myModule.directive("light", function(){ return { require: '^superman', link: function(scope, element, attrs, supermanCtrl){ supermanCtrl.addLight(); } } });
- 独立scope
1 <!-- IsolateScope.html --> 2 <!DOCTYPE html> 3 <html ng-app="MyModule"> 4 <head> 5 <meta charset="utf-8"> 6 <title></title> 7 <link rel="stylesheet" type="text/css" href="..\test01\css\bootstrap-3.3.0-dist\dist\css\bootstrap.css"> 8 </head> 9 <body> 10 <hello></hello> 11 <hello></hello> 12 <hello></hello> 13 <hello></hello> 14 </body> 15 <script type="text/javascript" src="../test01/js/angular.js"></script> 16 <script type="text/javascript" src="IsolateScope.js"></script> 17 </html>
//IsolateScope.js var myModule = angular.module("MyModule",[]); myModule.directive("hello", function(){ return { restrict: 'AE', scope: {}, //如果不加这个配置项,一个改变其他都会改变 template: '<div><input type="text" ng-model="userName"/>{{userName}}</div>', replace: true } });
- @: 把当前属性作为字符串传递。 你还可以绑定来自外层scope的值,在属性值中插入{{}}即可
1 <!-- ScopeAt.html --> 2 <!DOCTYPE html> 3 <html ng-app="MyModule"> 4 <head> 5 <meta charset="utf-8"> 6 <title></title> 7 <link rel="stylesheet" type="text/css" href="..\test01\css\bootstrap-3.3.0-dist\dist\css\bootstrap.css"> 8 </head> 9 <body> 10 <div ng-controller="MyCtrl"> 11 <drink flavor="{{ctrlFlavor}}"></drink> 12 </div> 13 </body> 14 <script type="text/javascript" src="../test01/js/angular.js"></script> 15 <script type="text/javascript"> 16 var myModule = angular.module("MyModule",[]); 17 myModule.controller('MyCtrl', ['$scope', function($scope){ 18 $scope.ctrlFlavor = "百威"; 19 }]) 20 // myModule.directive("drink", function(){ 21 // return { 22 // restrict: 'AE', 23 // template:"<div>{{flavor}}</div>", 24 // link: function(scope, element, attrs){ 25 // scope.flavor = attrs.flavor; 26 // } 27 // } 28 // }) 29 //以上可以直接写作: 30 myModule.directive("drink", function(){ 31 return { 32 restrict:'AE', 33 scope: { 34 flavor: '@' 35 }, 36 template: "<div>{{flavor}}</div>" 37 } 38 }) 39 </script> 40 </html>
- =: 与父scope中的属性进行双向绑定
1 <!-- ScopeEqual.html --> 2 <!DOCTYPE html> 3 <html ng-app="MyModule"> 4 <head> 5 <meta charset="utf-8"> 6 <title></title> 7 <link rel="stylesheet" type="text/css" href="..\test01\css\bootstrap-3.3.0-dist\dist\css\bootstrap.css"> 8 </head> 9 <body> 10 <div ng-controller="MyCtrl"> 11 Ctrl: 12 <br> 13 <input type="text" ng-model="ctrlFlavor"> 14 <br> 15 Directive: 16 <br> 17 <drink flavor="ctrlFlavor"></drink> 18 </div> 19 </body> 20 <script type="text/javascript" src="../test01/js/angular.js"></script> 21 <script type="text/javascript"> 22 var myModule = angular.module("MyModule",[]); 23 myModule.controller('MyCtrl', ['$scope', function($scope){ 24 $scope.ctrlFlavor = "百威"; 25 }]) 26 myModule.directive("drink", function(){ 27 return { 28 restrict:'AE', 29 scope: { 30 flavor: '=' 31 }, 32 template: '<input type="text" ng-model="flavor"/>' 33 } 34 }) 35 </script> 36 </html>
- &: 传递一个来自父scope的函数,稍后调用
1 <!-- ScopeAnd.html --> 2 <!DOCTYPE html> 3 <html ng-app="MyModule"> 4 <head> 5 <meta charset="utf-8"> 6 <title></title> 7 <link rel="stylesheet" type="text/css" href="..\test01\css\bootstrap-3.3.0-dist\dist\css\bootstrap.css"> 8 </head> 9 <body> 10 <div ng-controller="MyCtrl"> 11 <greeting greet="sayHello(name)"></greeting> 12 <greeting greet="sayHello(name)"></greeting> 13 <greeting greet="sayHello(name)"></greeting> 14 </div> 15 </body> 16 <script type="text/javascript" src="../test01/js/angular.js"></script> 17 <script type="text/javascript"> 18 var myModule = angular.module("MyModule",[]); 19 myModule.controller('MyCtrl', ['$scope', function($scope){ 20 $scope.sayHello = function(name){ 21 alert("Hello "+name); 22 } 23 }]) 24 myModule.directive("greeting", function(){ 25 return { 26 restrict:'AE', 27 scope: { 28 greet: '&' 29 }, 30 template: '<input type="text" ng-model="userName"/><br/>' + 31 '<button class="btn btn-default" ng-click="greet({name:userName})">Greeting</button><br>' 32 } 33 }) 34 </script> 35 </html>
- @: 把当前属性作为字符串传递。 你还可以绑定来自外层scope的值,在属性值中插入{{}}即可
- form指令
- HTML原生的form表单是不能嵌套的,而Angular封装之后的form可以嵌套
- Angular为form扩展了自动校验、防止重复提交等功能;
- Angular对input元素的type进行了校验,一共提供了以下10种类型:
text, number, url, email, radio, checkbox, hidden, button, submit, reset
- Angular为表单内置了4种CSS样式:
ng-valid, ng-invaid, ng-pristine, ng-dirty
-
内置校验器:
require, minlength, maxlength
1 <!-- FormBasic.html --> 2 <!DOCTYPE html> 3 <html ng-app="TestFormModule"> 4 <head> 5 <meta charset="utf-8"> 6 <script type="text/javascript" src="../test01/js/angular.js"></script> 7 </head> 8 <body> 9 <form name="myForm" ng-submit="save()" ng-controller="TestFormModule"> 10 <input type="text" name="userName" ng-model="user.userName" required/> 11 <input type="password" name="password" ng-model="user.password" required/> 12 <input type="submit" ng-disabled="myForm.$invalid" /> 13 </form> 14 </body> 15 <script type="text/javascript"> 16 var myModule = angular.module("TestFormModule",[]); 17 myModule.controller("TestFormModule", function($scope){ 18 $scope.user={ 19 userName:'xxxxx', 20 password:'' 21 }; 22 $scope.save=function(){ 23 alert("save!"); 24 } 25 }) 26 </script> 27 </html>
- 自定义指令
1 <!-- Expander.html --> 2 <!DOCTYPE html> 3 <html ng-app="expanderModule"> 4 <head> 5 <meta charset="utf-8"> 6 <script type="text/javascript" src="../test01/js/angular.js"></script> 7 </head> 8 <body> 9 <div ng-controller="SomeController"> 10 <expander class="expander" expander-title='title'> 11 {{text}} 12 </expander> 13 </div> 14 </body> 15 <script type="text/javascript"> 16 var myModule = angular.module("expanderModule",[]); 17 myModule.directive("expander", function(){ 18 return { 19 restrict: 'EA', 20 replace: true, 21 transclude: true, 22 scope: { 23 title : '=expanderTitle' 24 }, 25 template: '<div>' 26 + '<div class="title" ng-click="toggle()">{{title}}</div>' 27 + '<div class="body" ng-show="showMe" ng-transclude></div>' 28 + '</div>', 29 link: function(scope, element, attrs){ 30 scope.showMe = false; 31 scope.toggle = function(){ 32 scope.showMe = !scope.showMe; 33 } 34 } 35 } 36 }); 37 myModule.controller('SomeController', function($scope){ 38 $scope.title = '点击展开'; 39 $scope.text = '这里是内部的内容'; 40 }); 41 </script> 42 </html>
- 第三方指令库:angular-ui
12. Service和Provider:
- 使用$http服务
<!-- HTTPbasic.html --> <!DOCTYPE html> <html ng-app="MyModule"> <head> <meta charset="utf-8"> <script type="text/javascript" src="../test01/js/angular.js"></script> </head> <body> <div ng-controller="LoadDataCtrl"> <ul> <li ng-repeat="user in users"> {{user.name}} </li> </ul> </div> </body> <script type="text/javascript"> var myModule = angular.module("MyModule",[]); myModule.controller("LoadDataCtrl", ['$scope','$http',function($scope,$http){ $http({ method: 'GET', url: 'data.json' }).success(function(data, status, headers, config) { console.log("success..."); console.log(data); $scope.users=data; }).error(function(data, status, headers, config) { console.log("error..."); }); //这里会报错:$http(...).success is not a function。好像现在得用$http().then()function了? }]); </script> </html>
- 创建自己的Service
- Service的特性
- Service都是单例的
- Service由$injector负责实例化
- Service在整个应用的生命周期中存在,可以用来共享数据
- 在需要使用的地方利用依赖注入机制注入Service
- 自定义的Service需要写在内置的Service后面
- 内置Service的命名以$符号开头,自定义Service应该避免
- Service,Factory,Provider本质上都是Provider
function provider(name, provider_){ if(isFunction(provider_)){ provider_ = providerInjector.instantiate(provider_); } if(!provider_.$get){ throw Error('provider '+name+' must define $get factory...'); } return providerCache[name + providerSuffix] = provider_; }
- 使用$filter服务
- $filter是用来进行数据格式化的专用服务
- AngularJS内置了9个filter:
currency(格式化货币),data(日期),filter,json,limitTo,lowercase,number,orderBy,uppercase
- filter可以嵌套使用(用管道符号|分隔)
- filter是可以传递参数的
- 用户可以定义自己的filter
1 <!DOCTYPE html> 2 <html ng-app="MyModule"> 3 <head> 4 <meta charset="utf-8"> 5 <script type="text/javascript" src="../test01/js/angular.js"></script> 6 </head> 7 <body> 8 {{ 1304375948024 | date}} 9 <br> 10 {{ 1304375948024 | date:"MM/dd/yy @ h:mma"}} 11 <br> 12 {{ 1304375948024 | date:"yyyy-MM-dd hh:mm::ss"}} 13 </body> 14 <script type="text/javascript"> 15 var myModule = angular.module("MyModule",[]); 16 </script> 17 </html>
- 其他内置的Service介绍
13. 核心原理解析
- AngularJS的启动过程分析
- 依赖注入原理分析:Provider与Injector
- 指令的执行过程分析
- $scope与双向数据绑定分析