最近看了看angularjs,这里记录下,怕自己忘记。
目录
实际开发
目录架构
Angularjs也是延用了类似mvc的项目结构,view(html页面和模板),controller(js中的控制器模块),service(js中的服务),项目大体结构如下:
1. controllers该模块(文件夹)下都是项目的controller,作用是将view和service进行绑定与显示。
2. services该模块(文件夹)下,与服务端接口对接,获取数据。
3. xxx.html项目的入口文件,里面是所有js、controller、service等汇总文件
4. xxx.js全局js文件,与路由、拦截器等相关。
5. filters该模块(文件夹)下,是定义的过滤器(一般是自定义)
6. directives该模块(文件夹)下,是自定义的指令
路由ui-router
简介:
AngularUI库提供的最有用的库之一便是ui-router。angular-ui-router.js它是一个路由框架,允许你通过状态机
组织接口,而不是简单的URL路由。
1. 首先要引用该模块:
2. 路由要在其他模块开始前执行,在angular的config中进行配置,路由在控制器之上进行。
3. 默认路由
4. $stateProvider中的state属性的第一个参数
5. templateUrl属性获取外部模板,main.tpl是外部的html模板
6. controller属性
第一种方式:
第二种方式:
7. 在控制器和指令中进行路由跳转
点击去首页这个超链接,启动to方法,便可到达下面路由,并找到对应内容
8. 路由参数设置和$stateParams服务
9. 路由定义父子级嵌套
第一种方式:
Parent属性指定父级路由,子路由中的模板会在父路由的模板中的view视图下进行显示。
第二种方式:在子路由前加上父路由
10.多路由嵌套
如果页面是下面这种布局,常见的路由用法:
三个ui-view视图,下面state属性里用views进行多个嵌套,里面可以加templateUrl、controller等属性
点击视频超链接跳转video路由,此时之将right.tpl进行替换
11.多路由父子嵌套
实例:
<html>
<head>
<title>ui-router</title>
<script type="text/javascript"src="angular.js"></script>
<script type="text/javascript"src="angular-ui-router.js"></script>
</head>
<body >
<div ng-app="myApp">
<div ui-view></div> <!-- 视图 -->
</div>
</body>
<script type="text/javascript">
//定义模板,并注入ui-router
var app = angular.module('myApp', ['ui.router']);
//对服务进行参数初始化,这里配stateProvider服务的视图控制
app.config(["$stateProvider",'$urlRouterProvider', function ($stateProvider,$urlRouterProvider){
$urlRouterProvider.otherwise('/nv');
$stateProvider
.state("home2",{
url: '/default',
template:'<div>ss......</div>'
})
.state("home3",{
url: '/nv',
template:'<div>nv......</div>'
})
.state("home",{
url: '/main',
templateUrl:'main.tpl'
})
}]);
</script>
</html>
架构:
我们将路由放入一个类似XXX router.js中,并进行引用.
自定义服务
Factory:
使用angular.module的factory API创建服务,是最常见也是最灵活的方式:
angular.module('myApp.services', [])
.factory('githubService', function() {
var serviceInstance = {};
// 我们的第一个服务
return serviceInstance;
});
5种其他创建方式
在AngularJS应用中, factory()方法是用来注册服务的最常规方式,同时还有其他一些API
可以在特定情况下帮助我们减少代码量。
共有5种方法用来创建服务:
qfactory()
qservice()
qconstant()
qvalue()
qprovider()
Service方式:
架构:
我们将自定义服务放入一个类似XXXService.js中,并进行引用。可以设计成总的指令js,也可以每个模块写一个js并放在servicess文件夹下
控制器
简介:
除了孤立作用域外,所有的作用域都通过原型继承而来,也就是说它们都可以访问父级作用
域。如果熟悉面向对象编程,对这个机制应该不会陌生。
默认情况下, AngularJS在当前作用域中无法找到某个属性时,便会在父级作用域中进行查
找。如果AngularJS找不到对应的属性,会顺着父级作用域一直向上寻找,直到抵达$rootScope
为止。如果在$rootScope中也找不到,程序会继续运行,但视图无法更新。
通过例子来看一下这个行为。创建一个ParentController,其中包含一个user对象,再创
建一个ChildController来引用这个对象:
app.controller('ParentController', function($scope) {
$scope.person = {greeted: false};
});
app.controller('ChildController', function($scope) {
$scope.sayHello = function() {
$scope.person.name = 'Ari Lerner';
};
});
如果我们将ChildController置于ParentController内部,那ChildController的$scope
对象的父级作用域就是ParentController的$scope对象。根据原型继承的机制,我们可以在子
作用域中访问ParentController的$scope对象
实例:
varapp = angular.module('app', []);
app.controller('FirstController', function($scope) {
$scope.message = "hello";
});
架构:
我们将自定义控制器放入一个类似XXXController.js中,并进行引用。可以设计成总的指令js,也可以每个模块写一个js并放在controllers文件夹下
自定义指令
directive
directive()这个方法是用来定义指令的可以接受两个参数1. name(字符串)2. factory_function (函数)
angular.application('myApp',[])
.directive('myDirective', function() {
// 一个指令定义对象
return {
// 通过设置项来定义指令,在这里进行覆写
};
});
需要的设置项
可能的选项如下所示,每个键的值说明了可以将这个属性设置为何种类型或者什么样的
函数:
angular.module('myApp', [])
.directive('myDirective', function() {
return {
restrict: String,
priority: Number,
terminal: Boolean,
template: String or Template Function:
function(tElement, tAttrs) (...},
templateUrl: String,
replace: Boolean or String,
scope: Boolean or Object,
transclude: Boolean,
controller: String or
function(scope, element, attrs, transclude, otherInjectables) { ... },
controllerAs: String,
require: String,
link: function(scope, iElement, iAttrs) { ... },
compile: // 返回一个对象或连接函数,如下所示:
function(tElement, tAttrs, transclude) {
return {
pre: function(scope, iElement, iAttrs, controller) { ... },
post: function(scope, iElement, iAttrs, controller) { ... }
}
// 或者
return function postLink(...) { ... }
}
};
});
常用参数介绍
restrict是一个可选的参数。它告诉AngularJS这个指令在DOM中可以何种形式被声明。默
认AngularJS认为restrict的值是A,即以属性的形式来进行声明。
可选值如下:
E(元素)
<my-directive></my-directive>
A(属性,默认值)
<div my-directive="expression"></div>
C(类名)
<div class="my-directive:expression;"></div>
M(注释)
<--directive:my-directive expression-->
这些选项可以单独使用,也可以混合在一起使用:
angular.module('myDirective', function(){
return {
restrict: 'EA' // 输入元素或属性
};
});
上面的配置可以同时用属性或注释的方式来声明指令:
<-- 作为一个属性 -->
<div my-directive></div>
<-- 或者作为一个元素 -->
<my-directive></my-directive>
template参数是可选的,必须被设置为以下两种形式之一:
q 一段HTML文本;
q 一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个代表模板的字符
串。 tElement和tAttrs中的t代表template,是相对于instance的。在讨论链接和编译
设置时会详细介绍,模板元素或属性与实例元素或属性之间的区别。
AngularJS会同处理HTML一样处理模板字符串。模板中可以通过大括号标记来访问作用域,
例如{{ expression }}。
如果模板字符串中含有多个DOM元素,或者只由一个单独的文本节点构成,那它必须被包
含在一个父元素内。换句话说,必须存在一个根DOM元素:
template: '\
<div> <-- single root element -->\
<a href="http://google.com">Click me</a>\
<h1>When using two elements, wrap them in a parent element</h1>\
</div>\
另外,注意每一行末尾的反斜线,这样AngularJS才能正确解析多行字符串。在实际生产中,
更好的选择是使用templateUrl参数引用外部模板
templateUrl是可选的参数,可以是以下类型:
q 一个代表外部HTML文件路径的字符串;
q 一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个外部HTML文件
路径的字符串。
replace是一个可选参数,如果设置了这个参数,值必须为true,因为默认值为false。默
认值意味着模板会被当作子元素插入到调用此指令的元素内部:
<div some-directive></div>
.directive('someDirective', function() {
return {
template: '<div>some stuff here<div>'
};
});
调用指令之后的结果如下(这是默认replace为false时的情况):
<div some-directive>
<div>some stuff here<div>
</div>
如果replace被设置为了true:
.directive('someDirective', function() {
return {
replace: true // 修饰过
template: '<div>some stuff here<div>'
};
});
指令调用后的结果将是:
<div>some stuff here<div>。
transclude是一个可选的参数。如果设置了,其值必须为true,它的默认值是false;将transclude设为true后,在模板中加指令ng-transclude,页面上原内容将放入指令的标签中。
transclude:true,
template: '<div class="sidebox">\
<div class="content">\
<h2 class="header">{{ title }}</h2>\
<span class="content" ng-transclude>\
</span>\
</div>\
</div>'
};
controller:
controller参数可以是一个字符串或一个函数。当设置为字符串时,会以字符串的值为名字,
来查找注册在应用中的控制器的构造函数:
angular.module('myApp', [])
.directive('myDirective', function() {
restrict: 'A', // 始终需要
controller: 'SomeController'
})
// 应用中其他的地方,可以是同一个文件或被index.html包含的另一个文件
angular.module('myApp')
.controller('SomeController', function($scope, $element, $attrs, $transclude) {
// 控制器逻辑放在这里
});
可以在指令内部通过匿名构造函数的方式来定义一个内联的控制器:
angular.module('myApp',[])
.directive('myDirective', function() {
restrict: 'A',
controller:
function($scope, $element, $attrs, $transclude) {
// 控制器逻辑放在这里
}
});
我们可以将任意可以被注入的AngularJS服务传递给控制器。例如,如果我们想要将$log服
务传入控制器,只需简单地将它注入到控制器中,便可以在指令中使用它了。
控制器中也有一些特殊的服务可以被注入到指令当中。这些服务有:
1. $scope
与指令元素相关联的当前作用域。
2. $element
当前指令对应的元素。
3. $attrs
由当前元素的属性组成的对象。例如,下面的元素:
<div id="aDiv"class="box"></div>
具有如下的属性对象:
{
id: "aDiv",
class: "box"
}
4.$transclude
嵌入链接函数会与对应的嵌入作用域进行预绑定。
transclude链接函数是实际被执行用来克隆元素和操作DOM的函数。
作用域:
控制器中作用域关系:
除了孤立作用域外,所有的作用域都通过原型继承而来,也就是说它们都可以访问父级作用
域。
默认情况下, AngularJS在当前作用域中无法找到某个属性时,便会在父级作用域中进行查
找。如果AngularJS找不到对应的属性,会顺着父级作用域一直向上寻找,直到抵达$rootScope
为止。如果在$rootScope中也找不到,程序会继续运行,但视图无法更新。
利用属性的形式是继承隔离,
利用对象的形式是继承不隔离
1. 如果子作用域未自己定义属性,都是继承父作用域,则:父作用域属性改变,子作用域属性也会改变;子作用域属性改变,父作用域属性不改变。
2. 如果子作用域自己定义了属性,则:父作用域属性改变,子作用域属性不会改变;子作用域属性改变,父作用域属性不改变;即父作用域和子作用域只改变自己;
3. 利用js对象传值属性,在父作用域与定义对象及其属性,子作用域未自己定义属性,都是继承父作用域,则:父作用域属性改变,子作用域属性也会改变;子作用域属性改变,父作用域属性也改变。
4. 利用js对象传值属性,在父作用域与定义对象及其属性,子作用域继承对象并在对象中定义自己的属性,则:父作用域属性改变,子作用域属性不会改变;子作用域属性改变,父作用域属性不改变。
指令中作用域的关系:
Directive中的scope属性设置作用域的关系
1. scope为false时:这也是默认行为,指令中的作用域和控制器中作用域完全共享数据,即控制器中作用域编号,指令中作用域也变化;指令中作用域变化,控制器中也变化。
2. scope为true时:类似继承行为,及指令中作用域继承控制器中的作用域,具体看控制器中作用域关系中1、2两点。
3. scope为{ }时:完全隔离,即控制器作用域和指令作用域之间数据隔离,指令和指令作用域之间也数据隔离。
@:单项数据绑定,父影响子
=:双向数据绑定,父影响子,子影响父
&:调用父作用域方法
架构:
我们将自定义指令放入一个类似XXX Directive.js中,并进行引用。可以设计成总的指令js,也可以每个模块写一个js并放在directives文件夹下;restrict:'EA' // 一般用AE,templateUrl一般是指定外部模板
过滤器
AngularJS有很多实用的内置过滤器,同时也提供了方便的途径可以自己创建过滤器。
模板使用:
在HTML中的模板绑定符号{{ }}内通过|符号来调用过滤器,例如:
<!--显示: 123.46 -->
{{ 123.456789 | number:2 }}
Js调用:
在js代码中可以通过$filter来调用过滤器。例如,在js代码中使用lowercase
过滤器:
app.controller('DemoController', ['$scope', '$filter',
function($scope, $filter) {
$scope.name = $filter('lowercase')('Ari');
}]);
自定义过滤器:
过滤器本质上是一个会把我们输入的内容当作参数传入进去的函数。
angular.module('myApp.filters', [])
.filter('capitalize',function() {
return function(input) {
// input是我们传入的字符串
if (input) {
return input[0].toUpperCase() + input.slice(1);
}
});
现在,如果想将一个句子的首字母转换成大写形式,可以用过滤器先将整个句子都转换成小
写,再把首字母转换成大写:
<!-- Ginger loves dog treats -->
{{ 'ginger loves dog treats' | lowercase | capitalize }}
架构:
我们将自定义过滤器放入一个类似XXXfilter.js中,并进行引用。可以设计成总的过滤器js,也可以每个模块写一个js并放在filters文件夹下。
表单验证
Angular中新增了一个ngMessages指令,angular-messages.js,还要告诉Angular将ngMessages作为应用程序的依赖模块引入,就像这样:
angular.module('myApp', ['ngMessages']);
<formname="signup_form" novalidate ng-submit="signupForm()"
ng-controller="signupController">
<label>Yourname</label>
<input type="text" placeholder="Name"name="name" ng-model="signup.name" ng-minlength=
3 ng-maxlength=20 required />
<div class="error"ng-messages="signup_form.name.$error">
<div ng-message="required">Make sure you enter yourname</div>
<div ng-message="minlength">Your name must be at least 3characters</div>
<div ng-message="maxlength">Your name cannot be longer than 20characters</div>
</div>
<button type="submit">Submit</button>
</form>
拦截器
拦截器的核心是服务工厂,通过向$httpProvider.interceptors数组中添加服务工厂,在$httpProvider中进行注册。
一共有四种拦截器,两种成功拦截器,两种失败拦截器。
request
AngularJS通过$http设置对象来对请求拦截器进行调用。它可以对设置对象进行修改,或者创建
一个新的设置对象,它需要返回一个更新过的设置对象,或者一个可以返回新的设置对象的promise。
q response
AngularJS通过$http设置对象来对响应拦截器进行调用。它可以对响应进行修改,或者创建
一个新的响应,它需要返回一个更新过的响应,或者一个可以返回新响应的promise。
q requestError
AngularJS会在上一个请求拦截器抛出错误,或者promise被reject时调用此拦截器。
qresponseError
AngularJS会在上一个响应拦截器抛出错误,或者promise被reject时调用此拦截器。
调用模块的.factory()方法来创建拦截器,可以在服务中添加一种或多种拦截器:
angular.module('myApp', [])
.factory('myInterceptor', function($q) {
var interceptor = {
'request': function(config) {
// 成功的请求方法
return config; // 或者 $q.when(config);
},
'response': function(response) {
// 响应成功
return response; // 或者 $q.when(config);
},
'requestError': function(rejection) {
// 请求发生了错误,如果能从错误中恢复,可以返回一个新的请求或promise
return response; // 或新的promise
// 或者,可以通过返回一个rejection来阻止下一步
// return $q.reject(rejection);
},
'responseError': function(rejection) {
// 请求发生了错误,如果能从错误中恢复,可以返回一个新的响应或promise
return rejection; // 或新的promise
// 或者,可以通过返回一个rejection来阻止下一步
// return $q.reject(rejection);
}
};
return interceptor;
});
我们需要使用$httpProvider在.config()函数中注册拦截器:
angular.module('myApp', [])
.config(function($httpProvider) {
$httpProvider.interceptors.push('myInterceptor');
});