先来看一下 angular 的一般使用格式
//作用域定义 模块注入
angular.module('myApp', ['ui.bootstrap']);
//获取定义的App
var app = angular.module('myApp')
//anular 加载配置 拦截器与路由的配置一般在其中
app.config(funtion(){
});
//定义服务 (注入服务)
app.factory('net', funtion($http){
});
//定义指令 (注入服务)
app.directive('jsDate', function(){
});
//定义控制器 (注入服务)
app.controller('MainCtrl', function($scope){
});
//综合 angular的定义方法
function config(){
};
function myDirective(){
};
function myService(){
};
function myController(){
};
angular.module('myApp',['ui.bootstrap'])
.config(config)
.run(function ($rootScope, $state) {
$rootScope.$state = $state;
})
.factory('myService', myService)
.directive('myDirective', myDirective)
.controller('myController', myController);
$scope 是angular 中最为重要的服务,它代表着一般在angular的控制器中扮演着全局对象的作用。
下面使用实例演示$scope 的一些用法:
<input ng-model="person.name" type="text" placeholder="Yourname">
<h1>Hello {{person.name}}h1>
//$scope 的常见用法
//监视数据的变化 ng-change
$scope.$watch('bean', funtion(new,old){
});
//强制刷新数据 t= obj; t= function(){};
$scope.$apply(t)
$scope.$digest() 死循环来自动解析表达式
作用域(scope)①是构成AngularJS应用的核心基础. scope对象是定义应用业务逻辑、控制器方法和视图属性的地方。作用域是视图和控制器之间的胶水.作用域是应用状态的基础。基于动态绑定,我们可以依赖视图在修改数据时立刻更新 scope,
也可以依赖$scope在其发生变化时立刻重新渲染视图。作用域提供了监视数据模型变化的能力。
它允许开发者使用其中的apply机制,将数据模型的变化在整个应用范围内进行通知。
我们在作用域的上下文中定义和执行表达式,同时它也是将事件通知给另一个控制器和应用其他部分的中介。
将应用的业务逻辑都放在控制器中,而将相关的数据都放在控制器的作用域中,这是非常完美的架构。
注意:AngularJS启动并生成视图时,会将根ng-app元素同 rootScope进行绑定。 rootScope是所有$scope对象的最上层。
rootScope是AngularJS中最接近全局作用域的对象。在 rootScope上附加太多业务逻并不是好主意,这与污染JavaScript的全局作用域是一样的。
$scope 的生命周期
- 创建
**在创建控制器或指令时,AngularJS会用$injector创建一个新的作用域**
- 链接
- 更新
- 销毁
> $scope.$destory()
指令与控制器的作用域再其所在的Dom元素上
控制器在AngularJS中的作用是增强视图
控制器的嵌套
对于ng-app所处的层级来讲,它的父级作用域就是$rootScope
作用域的嵌套是通过DOM 元素的嵌套来完成的。
"ParentController">
<div ng-controller="ChildController">
<a ng-click="sayHello()">Say helloa>
div>
{{ person }}
div>
控制器应该尽可能保持短小精悍,而在控制器中进行DOM操作和数据操作则是一个不好的实践。
4. 指令 directive
4.1 常见内置指令
- ng-model ng-model-option
ng-model-options允许我们控制ng-model何时进行同步.
比如:1.当某个确定的事件被触发的时候 2.在指定的防抖动延迟时间之后,这样视图值就会在指定的时间之后被同步到模型.
失去焦点
ng-model-options="{ updateOn: 'default blur' }"
通过 debounce 延迟模型更新
ng-model-options="{debounce:1000}"
//通过 $rollbackViewValue方法 同步模型和视图
<div class="container" ng-controller="Rollback">
<form role="form" name="myForm2" ng-model-options="{ updateOn: 'blur' }">
<div class="form-group">
<label>执行了 $rollbackViewValue() 方法label>
<input name="myInput1" ng-model="myValue1" class="form-control" ng-keydown="resetWithRollback($event)">
<blockquote>
<footer>myValue1: "{{ myValue1 }}"footer>
blockquote>
<p>p>
div>
<div class="form-group">
<label>没有执行了 $rollbackViewValue() 方法label>
<input name="myInput2" ng-model="myValue2" class="form-control" ng-keydown="resetWithoutRollback($event)">
<blockquote>
<footer>myValue2: "{{ myValue2 }}"footer>
blockquote>
div>
form>
div>
app.controller('Rollback',function($scope){
$scope.resetWithRollback = function(e){
if(e.keyCode == 27) {
$scope.myForm2.myInput1.$rollbackViewValue();
}
};
$scope.resetWithoutRollback = function(e){
if(e.keyCode == 27){
angular.noop()
}
}
});
- ng-app ng-controller ng-view ng-include
- ng-switch 切换文本
<input type="text" ng-model="person.name"/>
<div ng-switch on="person.name">
<p ng-switch-default>And the winner isp>
<h1 ng-switch-when="Ari">{{ person.name }}h1>
div>
- ng-init
- {{ }} ng-bind 防闪动 ng-cloak
- ng-bind-template 用来在视图中绑定多个表达式
<div ng-bind-template="{{message}}{{name}}">div>
- ng-if ng-show ng-disabled ng-checked ng-readonly ng-selected
- ng-class ng-style
- ng-src ng-href
- ng-form ng-submit
- ng-click ng-dblclick
- ng-trim
- ng-repeat
- ng-select ng-option 下拉选择
<div ng-controller="CityController">
<select ng-model="city" ng-options="city.name for city in cities">
<option value="">Choose Cityoption>
select>
Best City: {{ city.name }}
div>
- ui-view 路由
- ng-change
- ng-keydown
4.2 自定义指令
注意:指令之前的嵌套
学习指令服务 我们先来看下面 指令所拥有的所有属性。
angular.module('myApp', [])
.directive('myDirective', function(){
return {
restrict:'EACM',
priority: Number, //优先级 默认为0
terminal: Boolean, //
template:'',
templateUrl: '',
replace: true,
scope:{
attr:'=',
ngModel:'=',//双向绑定
option:"@", //赋值
test:'&test' //对父级作用域进行绑定
},
link: function(scope, element, attr, ngModel){
},
controller: function($scope, $element, $attrs, $transclude){
},
controllerAs: String,
require: String/[], //依赖于另一个指令 require: '?ngModel',
//compile和link选项是互斥的。如果同时设置了这两个选项,那么会把compile所返回的函数当作链接函数,而link选项本身则会被忽略。
//
compile: function(tElement, tAttrs, transclude) {
}
}
});
注意要点:
- scope 的绑定使用
- link 与 compile 的深入理解
- require 依赖于其他指令的封装
- require: ‘?ngModel’ 单独理解
4.3 ngModel
ngModel是一个用法特殊的指令,它提供更底层的API来处理控制器内的数据。当我们在指令中使用ngModel时能够访问一个特殊的API,
这个API用来处理数据绑定、验证、CSS更新等不实际操作DOM的事情。
ngModel控制器会随ngModel被一直注入到指令中,其中包含了一些方法。
为了访问ngModelController必须使用require设置.
angular.module('myApp')
.directive('myDirective',function(){
return {
require: '?ngModel',
link: function(scope, ele, attrs, ngModel) {
if (!ngModel) return;
// 现在我们的指令中已经有ngModelController的一个实例
ngModel.$render = function() {
element.html(ngModel.$viewValue() || 'None');
};
}
};
});
ngModel 的属性
- $setViewValue()
- $viewValue $modelValue
二者都是ngmodel 的值 但是二者可能会不同
- $render
定义视图具体的渲染方式 慎用
- $parsers
函数组成的数组
- $formatters
- $viewChangeListeners
- $error
- $pristine
- $dirty
- $valid
- $invalid
5. 服务 service factory
5.1 内置服务
- $http ajax 服务请求
- $timeout 延迟执行
- $scope 作用域
- $rootScope 根作用于
- $intervel 心跳定时器
- $parse 手动解析表达式
- $interpolate (配合表达式的解析)
- $compile 重新构造作用域
$provide ,$compileProvider
angular.module('emailParser', [])
.config(['$interpolateProvider', function($interpolateProvider) {
$interpolateProvider.startSymbol('__');
$interpolateProvider.endSymbol('__');
}])
.factory('EmailParser', ['$interpolate', function($interpolate) {
// 处理解析的服务
return {
parse: function(text, context) {
var template = $interpolate(text);
return template(context);
}
};
}]);
angular.module('myApp', ['emailParser'])
.controller('MyController', ['$scope', 'EmailParser',
function ($scope, EmailParser) {
// 设置监听
$scope.$watch('emailBody', function (body) {
if (body) {
$scope.previewText = EmailParser.parse(body, {
to: $scope.to
});
}
});
}]
);
//现在用自定义的 __ 符号取代默认语法中的 {{ }} 符号来请求插值文本。
<div id="emailEditor">
<input ng-model="to" type="email" placeholder="Recipient" />
<textarea ng-model="emailBody">textarea>
div>
<div id="emailPreview">
<pre>__ previewText __pre>
div>
5.2 自定义服务
6. 常见过滤器的使用 $filter 服务
6.1 常见过滤器的使用
{{ name | uppercase }}
$scope.name = $filter('lowercase')('Ari');
- currency 货币
- date 日期
{{ today | date:'medium' }}
{{ today | date:'short' }}
{{ today | date:'fullDate' }}
{{ today | date:'longDate' }}
{{ today | date:'mediumDate' }}
{{ today | date:'shortDate' }}
{{ today | date:'mediumTime' }}
{{ today | date:'shortTime' }}
//年份格式化
四位年份:{{ today | date:'yyyy' }}
两位年份:{{ today | date:'yy' }}
一位年份:{{ today | date:'y' }}
//月份格式化
英文月份:{{ today | date:'MMMM' }}
英文月份简写:{{ today | date:'MMM' }}
数字月份:{{ today |date:'MM' }}
一年中的第几个月份:{{ today |date:'M' }}
//日期格式化
数字日期:{{ today|date:'dd' }}
一个月中的第几天:{{ today | date:'d' }}
英文星期:{{ today | date:'EEEE' }}
英文星期简写:{{ today | date:'EEE' }}
//小时格式化
24小时制数字小时:{{today|date:'HH'}}
一天中的第几个小时:{{today|date:'H'}}
12小时制数字小时:{{today|date:'hh'}}
上午或下午的第几个小时:{{today|date:'h'}}
// 分钟格式化
数字分钟数:{{ today | date:'mm' }}
一个小时中的第几分钟:{{ today | date:'m' }}
//秒数格式化
数字秒数:{{ today | date:'ss' }}
一分钟内的第几秒:{{ today | date:'s' }}
毫秒数:{{ today | date:'.sss' }}
// 字符格式化
上下午标识:{{ today | date:'a' }}
四位时区标识:{{ today | date:'Z' }}
下面是一些自定义日期格式的示例:
{{ today | date:'MMMd, y' }}
{{ today | date:'EEEE, d, M' }}
{{ today | date:'hh:mm:ss.sss' }}
filer
filter过滤器可以从给定数组中选择一个子集,并将其生成一个新数组返回
//string
{{ ['Ari','Lerner','Likes','To','Eat','Pizza'] | filter:'e' }}
//obj
{{ [{'name': 'Ari','City': 'San Francisco','favorite food': 'Pizza'},
{'name': 'Nate','City': 'San Francisco','favorite food': 'indian food'}] | filter:{'favorite food': 'Pizza'} }}
//自定义函数
{{ ['Ari','likes','to','travel'] | filter:isCapitalized }}
$scope.isCapitalized = function(str) {
return str[0] == str[0].toUpperCase();
};
json
son过滤器可以将一个JSON或JavaScript对象转换成字符串。这种转换对调试非常有帮助:
{{ {'name': 'Ari', 'City': 'SanFrancisco'} | json }}
limitTo
limitTo过滤器会根据传入的参数生成一个新的数组或字符串,新的数组或字符串的长度取决于传入的参数,通过传入参数的正负值来控制从前面还是从后面开始截取。
lowercase | uppercase
number 数组转换为纯文本 (参数用于控制小数点)
{{ 123456789 | number }}
{{ 1.234567 | number:2 }}
orderBy
orderBy过滤器可以用表达式对指定的数组进行排序。
orderBy可以接受两个参数,第一个是必需的,第二个是可选的。
第一个参数是用来确定数组排序方向的谓词。
第二个参数用来控制排序的方向(是否逆向)。
{{ [{'name': 'Ari','status': 'awake'},
{'name': 'Q','status': 'sleeping'},
{'name': 'Nate','status': 'awake'}] | orderBy:'name' }}
//结果反向
{{ [{'name': 'Ari','status': 'awake'},
{'name': 'Q','status': 'sleeping'},
{'name': 'Nate','status': 'awake'}] | orderBy:'name':true }}
6.2 自定义过滤器
angular.module('myApp.filters', [])
.filter('capitalize', function() {
return function(input) {};
});
6.3 表单验证
- required
- ng-minleng
- ng-maxleng
- ng-pattern
使用正则表达式
<input type="text" ng-pattern="[a-zA-Z]" />
- email
- number
- url
其他表单验证 以后在做讨论
7. 模块加载
服务与指令的注入与预编译实现
angular.module('myApp', [])
.config(function($provide ,$compileProvider) {
$provide.factory('myFactory', function() {
var service = {};
return service;
});
$compileProvider.directive('myDirective', function() {
return {
template: ''
};
});
});
内置路由
angular.module('myApp', [])
.config(function($routeProvider) {
$routeProvider.when('/', {
controller: 'WelcomeController',
template: 'views/welcome.html'
});
})
.config(function(ConnectionProvider) {
ConnectionProvider.setApiKey('SOME_API_KEY');
});
运行块
和配置块不同,运行块在注入器创建之后被执行,它是所有AngularJS应用中第一个被执行的方法。
运行块通常用来注册全局的事件监听器。例如,我们会在.run()块中设置路由事件的监听器以及过滤未经授权的请求。
假设我们需要在每次路由发生变化时,都执行一个函数来验证用户的权限,放置这个功能唯一合理的地方就是run方法:
angular.module('myApp', [])
.run(function($rootScope, AuthService) {
$rootScope.$on('$routeChangeStart', function(evt, next, current) {
// 如果用户未登录
if (!AuthService.userLoggedIn()) {
if (next.templateUrl === "login.html") {
// 已经转向登录路由因此无需重定向
} else {
$location.path('/login');
}
}
});
});
8. 多视图与路由
配置依赖 推荐使用 ui-view
<script src="js/vendor/angular-route.js">script>
angular.module('myApp', ['ngRoute']);
<div ng-view>div>
完整配置
angular.module('myApp', []).config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/home.html',
controller: 'HomeController'
})
.when('/login', {
templateUrl: 'views/login.html',
controller: 'LoginController'
})
.when('/dashboard', {
templateUrl: 'views/dashboard.html',
controller: 'DashboardController',
resolve: {
user: function (SessionService) {
return SessionService.getCurrentUser();
}
}
})
.otherwise({
redirectTo: '/'
});
}]);
路由中的配置:
- controller
- template
- templateUrl
- resolve
如果设置了resolve属性,AngularJS会将列表中的元素都注入到控制器中。
resolve: {
'data': ['$http', function($http) {
return $http.get('/api').then(
function success(resp) { return response.data; },
function error(reason) { return false; }
);
}];
}
- redirectTo 重定向
redirectTo: '/home'
// 或者
redirectTo: function(route,path,search)
- reloadOnSearch boolean true $location.search()发生变化时会重新加载路由。
- $routeParams
前面提到如果我们在路由参数的前面加上:,AngularJS就会把它解析出来并传递给$routeParams。
$routeProvider
.when('/inbox/:name', {
controller: 'InboxController',
templateUrl: 'views/inbox.html'
});
$location 服务
- path()
- replace() uwfa后退
- absUrl() 编码后的完整URL
- hash()
- host()
- port()
- protocol() URL 协议
- search() 查询串
- url()
标签路由模式
指定路由模式
下面这种方式是使用默认的标签模式,即在url 加 # 来区分路由
angular.module('myApp', ['ngRoute'])
.config(['$locationProvider', function($locationProvider) {
$locationProvider.html5Mode(false);
$locationProvider.hashPrefix('!'); //改变默认# 为!
}]);
HTML5 路由模式
这种模式下 URL 看起来与普通的URL 一样没有区别
同样在angular 中配置路由模式
angular.module('myApp', ['ngRoute'])
.config(['$locationProvider', function($locationProvider) {
$locationProvider.html5Mode(true);
}]);
9. 依赖注入
一个对象通常有三种方式可以获得对其依赖的控制权:
(1) 在内部创建依赖;
(2) 通过全局变量进行引用;
(3) 在需要的地方通过参数进行传递。
依赖注入是通过第三种方式实现的。其余两种方式会带来各种问题,例如污染全局作用域,使隔离变得异常困难等。
依赖注入是一种设计模式,它可以去除对依赖关系的硬编码,从而可以在运行时改变甚至移除依赖关系。
AngularJS使用 injetor(注入器服务)来管理依赖关系的查询和实例化。事实上, injetor负责实例化AngularJS中所有的组件,包括应用的模块、指令和控制器等。