Angular
简介
js 是基础,angularJs 是 js 框架
起源
- 2009年Google Feedback Project
- 将6个月开发的17000行前端代码,使用3周压缩到1500行
简介
- Angularjs 致力于减轻开发人员在开发AJAX应用过程中的痛苦
- 官网:http://www.angularjs.org/
ajax 开发是单页应用
概念
- 客户端模版
- MVC
- 数据绑定
- 依赖注入
客户端模版
- Angular中,模版和数据都会被发送到浏览器中,然后在客户端进行装配
【以前模板和数据是在后端装配完的,如servlet】
MVC
- MVC核心概念:把管理数据的代码(model)、应用逻辑代码(controller)、向用户展示数据的代码(view)清晰地分离开
- Angularjs应用中:
视图就是Document Object Model
控制器就是Javascript类
模型数据则被存储在对象的属性中
数据绑定
- 数据绑定可自动将model和view间的数据同步。
- Angular实现数据绑定的方式,可以让我们把model当作程序中唯一可信的数据来源。view始终是model的投影。当model发生变化时,会自动反映到view上。
经典模板系统中的数据绑定
大多数模板系统中的数据绑定都是单向的
- 把模板与model合并在一起变成view,如果在合并之后,model发生了变化,不会自动反映到view上。
- 用户在view上的交互也不会反映到model中,开发者必须写大量代码不断地在view与model之间同步数据。
Anguarjs 模板中的数据绑定
模板是在浏览器中编译的,在编译阶段产生了一个实时更新(live)的视图
- 不论在model或是view上发生了变化,都会立刻反映到对方。
- model成为程序中唯一真实的数据来源,极大地简化了开发者需要处理的编程模型。
依赖注入
依赖注入是一种软件设计模式,用来处理代码的依赖关系。【如java spring Ioc】
- Angular的依赖注入只是简单的获取它所需要的东西,而不需要创建那些他们所依赖的东西
Demo 001-依赖注入
- <!DOCTYPE html>
- <html>
- <head>
- <title>Angularjs-视频教程-001-简介</title>
- </head>
- <body>
- <script>
- var A = function () {
- this.getName = function () {
- return '张三';
- }
- }
- var a = new A;
- var B = function () {
- // B 依赖于 a,b对象中需要用到a对象
- document.write(a.getName());
- }
- // a 注入 b,将a传入b对象中
- var b = new B();
- //在用b对象时需要用到a对象 ,js里2个方法实现:
- // 1. 将a 传入到b里面去
- // 2. a是全局变量
- </script>
- </body>
- </html>
指令
ng-app
- ng-app指令告诉Angular应该管理页面中的哪一块
【写在body里面,管理整个body里面的元素,管理整个页面】
模版显示文本 && ng-bind
- {{expression}}【写在双大括号里面的是表达式】
- <tag ng-bind="expression"></tag>
Demo 002--数据双向绑定:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body ng-app>
<!--
view => 12131
model => 12131
3个 view
数据是双向绑定的
-->
<input type="text" ng-model="name" value=""/>
<!--angular的表达式-->
{{ name }}
<input type="text" ng-model="name" value=""/>
<script type="text/javascript" src="../vendor/angular/angularjs.js"></script>
</body>
</html>
javascript 表达式
创建一个字符串,使用函数eval解析
- var str = 'alert(1+2)';
- eval(str)
angular 表达式
- angular 表达式 通过$parse服务解析执行。
- 与Javascript 表达式的区别:
1.属性求值:所有属性的求值是对于scope的,而javascript是对于window对象的。
【var a=3,是针对window的属性】
2.宽容:表达式求值,对于undefined和null,angular是宽容的,但Javascript会产生NullPointerExceptions=
3.没有流程控制语句:在angular表达式里,不能做以下任何的事:条件分支、循环、抛出异常
4.过滤器(filters):我们可以就将表达式的结果传入过滤器链(filter chains)
ng-controller
- 控制器就是你所编写的类或者类型,它的作用是告诉Angular该模型是由哪些对象或者基本数据结构构成的
Demo 003--控制器
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="">
<div ng-controller="firstController">
<input type="text" value="" ng-model="name"/>
<input type="text" value="" ng-model="age"/>
{{name}}
{{age}}
</div>
</div>
<script type="text/javascript" src="app/index.js"></script>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
</body>
</html>
var firstController = function($scope){
//$scope 我们叫做作用域,是管理firstController控制器范围所有的数据的作用域,和js函数的作用域一样
// 申明一个默认的Model
$scope.name = '张三';
$scope.age = 20;
}
Demo 005-多个控制器 作用域链的问题
AngularJs 多个controller作用域和 js 函数变量左右域的原理类似, 函数里面使用变量的时候,优先找函数作用域里面的是否有该变量,如果没有,就去访问函数外面的变量.
下面的demo中,总共有三个作用域,一个是ng-app, 另外两个分别是firstController、secondController
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="">
<div ng-controller="firstController">
<input type="text" value="" ng-model="name"/>
<div ng-controller="secondController">
<input type="text" value="" ng-model="name"/>
</div>
</div>
</div>
<script>
function first(){
var name = '张三';
function second(){
var name = '张三12121212121';
alert(name);
}
}
</script>
<script type="text/javascript" src="app/index.js"></script>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
</body>
</html>
Index.js
var firstController = function($scope){
$scope.name = '张三';
console.log($scope);
}
var secondController = function($scope){
console.log($scope);
}
ng-bind
ng-bind 也可以展现$scope里面的数据,比{{}} 展示数据的优势在于,使用ng-bind,当angularJs 没有加载完的时候,不会显示任何东西,而使用{{}},会显示乱码
$scope
什么是 scope
- scope是一个指向应用model的object,也是表达式的执行上下文。
- scope被放置于一个类似应用的DOM结构的层次结构中。
- scope 类似js 的作用域链
scope的特性
- scope提供$watch API,用于监测model的变化。
- scope提供$apply,在"Angular realm"(controller、server、angular event handler)之外,从系统到视图传播任何model的变化。
- scope可以在提供到被共享的model属性的访问的时候,被嵌入到独立的应用组件中。scope通过(原型),从parent scope中继承属性。
$apply
【$apply方法有什么用?当apply 方法执行完之后,会触发angular里面的脏检查,检查每一个scope里面的属性是否有变化,如果有变化,所对应的其他的model 、value 都会变化】
- $scope.$apply(expression)
- $apply()方法可以在angular框架之外执行angular JS的表达式,例如:DOM事件、setTimeout、XHR或其他第三方的库
angular是怎么知道变量发生了改变
- 要知道一个变量变了,方法不外乎两种
- 1.能通过固定的接口才能改变变量的值,比如说只能通过 set() 设置变量的值,set被调用时比较一下就知道了。这中方法的缺点洗是写法繁琐
- 2.脏检查,将原对象复制一份快照,在某个时间,比较现在对象与快照的值,如果不一样就表明发生变化,这个策略要保留两份变量,而且要遍历对象,比较每个属性,这样会有一定性能问题
angular的策略
- angular的实现是使用脏检查
- angular的策略
1.不会脏检查所有的对象,当对象被绑定到html中,这个对象添加为检查对象(watcher)。
2.不会脏检查所有的属性,同样当属性被绑定后,这个属性会被列为检查的属性。 - 在angular程序初始化时,会将绑定的对象的属性添加为监听对象(watcher),也就是说一个对象绑定了N个属性,就会添加N个watcher。
什么时候去脏检查
- angular 所系统的方法中都会触发比较事件,比如:controller 初始化的时候,所有以ng-开头的事件执行后,都会触发脏检查
手动触发脏检查
- $apply仅仅只是进入angular context ,然后通过$digest去触发脏检查
- $apply如果不给参数的话,会检查该$scope里的所有监听的属性,推荐给上参数
【只有需要手动触发的时候脏检查,才需要调用apply方法。否则,比如,:controller 初始化的时候,系统会自动在后台调用apply方法。】
Demo 006-$scope里$apply、$digest方法
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="">
<div ng-controller="firstController">
{{date}}
</div>
</div>
<script type="text/javascript" src="app/index.js"></script>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
</body>
</html>
Index.js
var firstController = function($scope){
$scope.date = new Date();
// setInterval(function(){
// // 这里虽然变 但是并没有触发 脏检查
// $scope.date = new Date();
// },1000)
setInterval(function(){
$scope.$apply(function(){
$scope.date = new Date(); //....会去触发脏检查
})
},1000) // 触发一次脏检查
}
$digest()
- 所属的scope和其所有子scope的脏检查,脏检查又会触发$watch(),整个Angular双向绑定机制就活了起来~
- 查看$apply方法源代码可以知道,不建议直接调用$digest(),而应该使用$apply(),$apply其实不能把信直接送给$digest,之间还有$eval门卫把关,如果$apply带的表达式不合法,$eval会把错误送交$exceptionHandler,合法才触发digest,所以更安全
$watch
- 在digest执行时,如果watch观察的value与上次执行时不一样时,就会被触发
- AngularJS内部的watch实现了页面随model的及时更新
函数
- $watch(watchFn,watchAction,deepWatch)
参数:
watchFn: angular表达式或函数的字符串【表达式是有上下文关系的】
watchAction(newValue,oldValue,scope): watchFn发生变化会被调用
deepWacth: 可选的,布尔值命令检查被监控的对象的每个属性是否发生变化 - $watch会返回一个函数,想要注销这个watch可以使用函数
Demo 007-$scope里的$watch方法
应用场景,可以是购物车 当你购买到一定数量的商品的时候,折扣发生变化。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="">
<div ng-controller="firstController">
<input type="text" value="" ng-model="name"/>
改变次数:{{count}}-{{name}}
</div>
</div>
<script type="text/javascript" src="app/index.js"></script>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
</body>
</html>
var firstController = function($scope){
$scope.name = '张三';
$scope.data = {
name :'李四',
count:20
}
$scope.count = 0;
// 监听一个model【变量】, 当一个model每次改变时 都会触发第2个函数
$scope.$watch('name',function(newValue,oldValue){
++$scope.count;
if($scope.count > 30){
$scope.name = '已经大于30次了';
}
});
//监听的是data是一个对象,如果要监听date中的name、age变化,那么第三个参数必须设置为true才行
$scope.$watch('data',function(){},true)
}
ng-repeat 指令 重复 HTML 元素
ng-repeat 指令用在一个对象数组上:
<div ng-app="" ng-init="names=[
{name:'Jani',country:'Norway'},
{name:'Hege',country:'Sweden'},
{name:'Kai',country:'Denmark'}]">
<p>循环对象:</p>
<ul>
<li ng-repeat="x in names">
{{ x.name + ', ' + x.country }}
</li>
</ul>
</div>
ng-repeat指令会重复一个 HTML 元素:
<div ng-app="" ng-init="names=['Jani','Hege','Kai']">
<p>使用 ng-repeat 来循环数组</p>
<ul>
<li ng-repeat="x in names">
{{ x }}
</li>
</ul>
</div>
Demo 综合练习 008~011-练习 购物车
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="../../vendor/bootstrap3/css/bootstrap.min.css"/>
</head>
<body ng-app>
<div ng-controller="cartController" class="container">
<table class="table" ng-show="cart.length">
<thead>
<tr>
<th>产品编号</th>
<th>产品名字</th>
<th>购买数量</th>
<th>产品单价</th>
<th>产品总价</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in cart">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>
<button type="button" ng-click="reduce(item.id)" class="btn tn-primary">-</button>
<input type="text" value="{{item.quantity}}" ng-model="item.quantity" >
<button type="button" ng-click="add(item.id)" class="btn tn-primary">+</button>
</td>
<td>{{item.price}}</td>
<td>{{item.price * item.quantity}}</td>
<td>
<button type="button" ng-click="remove(item.id)" class="btn btn-danger">移除</button>
</td>
</tr>
<tr>
<td>
总购买价
</td>
<td>
{{totalPrice()}}
</td>
<td>
总购买数量
</td>
<td>
{{totalQuantity()}}
</td>
<td colspan="2">
<button type="button" ng-click="cart = {}" class="btn btn-danger">清空购物车</button>
</td>
</tr>
</tbody>
</table>
<p ng-show="!cart.length">您的购物车为空</p>
</div>
<script type="text/javascript" src="app/index.js"></script>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
</body>
</html>
Js文件
var cartController = function ($scope) {
$scope.cart = [
{
id: 1000,
name: 'iphone5s',
quantity: 3,
price: 4300
},
{
id: 3300,
name: 'iphone5',
quantity: 30,
price: 3300
},
{
id: 232,
name: 'imac',
quantity: 4,
price: 23000
},
{
id: 1400,
name: 'ipad',
quantity: 5,
price: 6900
}
];
/**
* 计算购物总价
*/
$scope.totalPrice = function () {
var total = 0;
angular.forEach($scope.cart, function (item) {
total += item.quantity * item.price;
})
return total;
}
/**
* 计算总购买数
*/
$scope.totalQuantity = function () {
var total = 0;
angular.forEach($scope.cart, function (item) {
total += parseInt(item.quantity);
})
return total;
}
/**
* 找一个元素的索引
*/
var findIndex = function (id) {
var index = -1;
angular.forEach($scope.cart, function (item, key) {
if (item.id === id) {
index = key;
return;
}
});
return index;
}
/**
* 为某个产品添加一个数量
*/
$scope.add = function (id) {
var index = findIndex(id);
if (index !== -1) {
++$scope.cart[index].quantity;
}
}
/**
* 为某个产品减少一个数量
*/
$scope.reduce = function (id) {
var index = findIndex(id);
if (index !== -1) {
var item = $scope.cart[index];
if(item.quantity > 1){
--item.quantity;
}else{
var returnKey = confirm('是否从购物车内删除该产品!');
if(returnKey){
$scope.remove(id);
}
}
}
}
/**
* 移除一项
*/
$scope.remove = function (id) {
var index = findIndex(id);
// 如果找到了那个item
if (index !== -1) {
$scope.cart.splice(index, 1);
}
//ng-click ,是ng开头的,调用之后,会自动做脏检查。会更新所有的参数、表达式值,这就是双向绑定的好处。
}
// 监听数量 如果小于 1 则让用户判断是否要删除产品
$scope.$watch('cart',function(newValue,oldValue){
angular.forEach(newValue,function(item,key){
if(item.quantity < 1){
var returnKey = confirm('是否从购物车内删除该产品!');
if(returnKey){
$scope.remove(item.id);
}else{
item.quantity = oldValue[key].quantity;
}
}
})
},true);
}
scope生命周期
- 1.用户请求应用起始页
- 2.angular 被加载,查找ng-app指令
- 3.Angular 遍历模版,查找指令
- 4.controller被启用,$scope被注入进来
- 5.在模版link过程中,指令在scope中注册$watch。这些watch将会被用作向DOM传播model的值。
- 5.当在controller中做同步的工作时angular API 已经隐式地做了$apply操作
- 6.在$apply的结尾,angular会在root scope执行一个$digest周期,这将会传播到所有child scope中。在$digest周期中,所有注册了$watch的表达式或者function都会被检查,判断model是否发生了改变,如果改变发生了,那么对应的$watch监听器将会被调用。
- 7.当child scope不再是必须的时候,child scope的产生者有责任通过scope.$destroy() API销毁它们(child scope)。这将会停止$digest的调用传播传播到child scope中,让被child scope model使用的内存可以被gc回收。
$eval && $evalAsync
- 在作用域的上下文中执行表达式
- $eval(expression)
- $evalAsync接受一个函数,把它列入计划,在当前正持续的digest中或者下一次digest之前执行,即使它已经被延迟了,仍然会在现有的digest遍历中被执行,类似于settimeout(fun,0)
$broadcast && $emit && $on
- $broadcast:会把事件广播给所有子controller
- $emit:则会将事件冒泡传递给父controller
- $on:是angular的事件注册函数
- 可以简单实现解决angular controller之间的通信
- 事件也会产生一个event对象,类似与dom中的事件冒泡等机制
$new && $destroy
- $new 创建一个新的作用域
- $destory 销毁一个作用域
- 作用域的继承是类似于javascript的原型继承,会有类似的原型链
Module 模块 (视频12)
AngularJS中的Module类负责定义应用如何启动,它还可以通过声明的方式定义应用中的各个片段。我们来看看它是如何实现这些功能的。
一.Main方法在哪里
如果你是从Java或者Python编程语言转过来的,那么你可能很想知道AngularJS里面的main方法在哪里?这个把所有东西启动起来,并且第一个被执行的方法在哪里?JavaScript代码里面负责实例化并且把所有东西组合到一起,然后命令应用开始运行的那个方法在哪里?
事实上,AngularJS并没有main方法,AngularJS使用模块的概念来代替main方法。模块允许我们通过声明的方式来描述应用中的依赖关系,以及如何进行组装和启动。使用这种方式的原因如下:
1.模块是声明式的。这就意味着它编写起来更加容易,同时理解起来也很容易,阅读它就像读普通的英文一样!
2.它是模块化的。这就迫使你去思考如何定义你的组件和依赖关系,让它们变得更加清晰。
3.它让测试更加容易。在单元测试中,你可以有选择地加入模块,并且可以避免代码中存在无法进行单元测试的内容。同时,在场景测试中,你可以加载其他额外的模块,这样就可以更好地和其他组件配合使用。
例如,在我们的应用中有一个叫做"MyAwesomeApp"的模块。在HTML里面,只要把以下内容添加到<html>标签中(或者从技术上说,可以添加到任何标签中):
<html ng-app="MyAwesomeApp">
ng-app指令就会告诉AngularJS使用MyAwesomeApp模块来启动你的应用。那么,应该如何定义模块呢?举例来说,我们建议你为服务、指令和过滤器分别定义不同的模块。然后你的主模块可以声明依赖这些模块。
这样可以使得模块管理更加容易,因为它们都是良好的、完备的代码块,每个模块有且只有一种职能。同时,单元测试可以只加载它们所关注的模块,这样就可以减少初始化的次数,单元测试也会变得更精致、更专注。
二.加载和依赖
模块加载动作发生在两个不同的阶段,这一点从函数名上面就可以反映出来,它们分别是Config代码块和Run代码块(或者叫做阶段)。
1.Config代码块
在这一阶段里面,AngularJS会连接并注册好所有数据源。因此,只有数据源和常量可以注入到Config代码块中。那些不确定是否已经初始化好的服务不能注入进来。
2.Run代码块
Run代码块用来启动你的应用,并且在注射器创建完成之后开始执行。为了避免在这一点开始之后再对系统进行配置操作,只有实例和常量可以被注入到Run代码块中。你会发现,在AngularJS中,Run代码块是与main方法最类似的东西。
三.快捷方法
利用模块可以做什么呢?我们可以用它来实例化控制器、指令、过滤器以及服务,但是利用模块类还可以做更多事情。如下模块配置的API方法:
1.config(configFn)
利用此方法可以做一些注册工作,这些工作需要在模块加载时完成。
http://www.cnblogs.com/sean-/p/4952183.html、
什么是Module
- 大部分应用都有一个主方法(main)用来实例化、组织、启动应用。
- AngularJS应用没有主方法,而是使用模块来声明应用应该如何启动。
- 模块允许通过声明的方式来描述应用中的依赖关系,以及如何进行组装和启动
Angular 模块
- 模块是组织业务的一个框框,在一个模块当中定义多个服务。当引入了一个模块的时候,就可以使用这个模块提供的一种或多种服务了。
- AngularJS 本身的一个默认模块叫做 ng ,它提供了 $http , $scope等等服务
- 服务只是模块提供的多种机制中的一种,其它的还有指令( directive ),过滤器( filter ),及其它配置信息。
- 也可以在已有的模块中新定义一个服务,也可以先新定义一个模块,然后在新模块中定义新服务。
- 服务是需要显式地的声明依赖(引入)关系的,让 ng 自动地做注入
Module优点
- 启动过程是声明式的,更容易懂。
- 在单元测试是不需要加载全部模块的,因此这种方式有助于写单元测试。
- 可以在特定情况的测试中增加额外的模块,这些模块能更改配置,能帮助进行端对端的测试。
- 第三方代码可以作为可复用的module打包到angular中
- 模块可以以任何先后或者并行的顺序加载(因为模块的执行本身是延迟的)。
ng-app
- 通过ng-app指定对应的模块应用启动
定义模块
- angular.module(name, [requires], configFn);
参数:
- name:定义的模块名
- requires:该模块所依赖的模块,如果,没有依赖的模块填[]
- configFn 会在模块初始化时执行,可以在里配置模块的服务
- configFn @see angular.config()
Demo 012-模块和控制器
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<!--这块区域由myApp 模块来管理-->
<!--一个页面中不能有多个ng-app ,模块也不能嵌套-->
<div ng-app="myApp">
<div ng-controller="firstController">
{{name}}
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<!--index.js文件不能放在angularjs.js 文件之前,否则读取 index.js文件的内容的时候,还没有读取angularjs.js,而报错-->
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
//模块创建完之后,返回模块对象,赋值给myApp
var myApp = angular.module('myApp',[]);
//这样写表示,firstController控制器是属于,myApp模块的
myApp.controller('firstController',function($scope){
$scope.name = '张三';
});
定义服务 $provider
- 服务本身是一个任意的对象。
- ng 提供服务的过程涉及它的依赖注入机制。
- angular 是用$provider对象来实现自动依赖注入机制,注入机制通过调用一个 provider 的 $get() 方法,把得到的对象作为参数进行相关调用
- $provider.provider 是一种定义服务的方法 , $provider还提供了很多很简便的方法,这些简便的方法还直接被module所引用
Demo 013-$provide里provider方法
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp">
<div ng-controller="firstController">
{{name}}
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
//因模块先于controller执行,故在模块启动的时候,我们可以在模块中配置一些相关的信息,给controller使用
var myApp = angular.module('myApp',[],function($provide){
//自定义服务,模块myApp定义好服务CustomService之后,在模块的任意的controller中都可以调用该服务。
$provide.provider('CustomService',function(){//服务名:CustomService
this.$get = function(){
return {
message : 'CustomService Message'
}
}
});
$provide.provider('CustomService2',function(){
this.$get = function(){
return {
message : 'CustomService2 Message'
}
}
});
});
myApp.controller('firstController',function(CustomService,$scope,CustomService2){//参数的顺序遂意
$scope.name = '张三';
console.log(CustomService2);
});
$provider.factory
- factory 方法直接把一个函数当成是一个对象的 $get() 方法
- @see module.factory
- 返回的内容可以是任何类型
$provider.service
- 和factory类似,但返回的东西必须是对象
- @see module.service
Demo 014-$provide里factory、service方法
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp">
<div ng-controller="firstController">
{{name}}
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
var myApp = angular.module('myApp',[],function($provide){
// 自定义服务
$provide.provider('CustomService',function(){
this.$get = function(){
return {
message : 'CustomService Message'
}
}
});
// 自定义工厂,返回的内容可以是任何类型
$provide.factory('CustomFactory',function(){
return [1,2,3,4,5,6,7];
});
// 自定义服务
$provide.service('CustomService2',function(){
return 'aaa';//l 和factory类似,但返回的东西必须是对象,不能事字符串、数字等基本类型。数组是引用类型
})
});
myApp.controller('firstController',function($scope,CustomFactory,CustomService2){
$scope.name = '张三';
console.log(CustomFactory);
console.log(CustomService2);
});
Demo 015-多个控制器内共享数据
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp">
<!--两个Controller不存在包含关系,存在两个$scope 域-->
<div ng-controller="firstController">
first.data <input type="text" ng-model="data.name" />
first.Data <input type="text" ng-model="Data.message" />
<p>
first-name:{{data.name}}
</p>
<p>
first-message:{{Data.message}}
</p>
</div>
<div ng-controller="secondController">
<p>
second-name:{{data.name}}
</p>
<p>
second-message:{{Data.message}}
</p>
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
angular.module('myApp',[])
.factory('Data',function(){ // this.$get = function(){}
return {
message : '共享的数据'
};
})
.controller('firstController',function($scope,Data){
$scope.data = {//对象,引用类型,一个地方变了,全部都变了
name : '张三'
};
$scope.Data = Data;
})
.controller('secondController',function($scope,Data){
$scope.data = $scope.$$prevSibling.data;//prevSibling上一个sope域中的数据
$scope.Data = Data;
});
显式和隐式依赖注入
- 把service当作被依赖的资源加载到controller中的方法,与加载到其他服务中的方法很相似。
- javascript是一个动态语言,DI不能弄明白应该通过参数类型注入哪一个service
- 显式依赖:要通过$inject属性指定service名称, 它是一个包含需要注入的service名称的字符串数组,工厂方法中的参数顺序,与service 在数组中的顺序一致。
- 隐式依赖:则允许通过参数名称决定依赖,$scope
Filters
什么是angular 过滤器
- 是用于对数据的格式化,或者筛选的函数,可以直接在模板中通过一种语法使用
- {{ expression | filter }}
- {{ expression | filter1 | filter2 }}
- {{ expression | filter1:param,….}}【参数使用冒号分割】
过滤器种类
- Number:数字格式化
- currency:货币格式化
- date: 日期格式化
- limitTo: 截取数据
- lowercase
- uppercase
- filter
- json
- orderBy
017-过滤器 limitTo、lowercase、uppercase 、filter 、orderBy、json
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp">
<div ng-controller="firstController">
<!--[1,2,3,4,5] 显示前5位-->
<p>{{[1,2,3,4,5,6,7] | limitTo:5}}</p>
<!--[3,4,5,6,7],显示最后五位-->
<p>{{[1,2,3,4,5,6,7] | limitTo:-5}}</p>
<!-- hello world -->
<p>{{data.message | lowercase}}</p>
<!-- HELLO WORLD -->
<p>{{data.message | uppercase}}</p>
<p>
<!-- [{"name":"上海11212","py":"shanghai"}],【过滤包含:上海的项】-->
{{ data.city | filter : '上海'}}
</p>
<p>
<!-- [],【只匹配value值】-->
{{ data.city | filter : 'name'}}
</p>
<p>
<!-- name":"上海11212","py":"shanghai"},{"name":"北京","py":"beijing"},【拼音里面是否有g】-->
{{ data.city | filter : {py:'g'} }}
</p>
<p>
<!-- [{"name":"上海11212","py":"shanghai"},{"name":"四川","py":"sichuan"}]-->
{{ data.city | filter : checkName }}
</p>
<p>
<!-- [{"name":"北京","py":"beijing"},{"name":"上海11212","py":"shanghai"},{"name":"四川","py":"sichuan"}] -->
<!-- 默认顺序是 正序 asc a~z 【按照拼音排序】 -->
{{ data.city | orderBy : 'py'}}
<!-- 默认顺序是 反序 desc z~a -->
<!-- [{"name":"四川","py":"sichuan"},{"name":"上海11212","py":"shanghai"},{"name":"北京","py":"beijing"}] -->
{{ data.city | orderBy : '-py'}}
</p>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
angular.module('myApp',[])
.factory('Data',function(){
return {
message : 'Hello World',
city : [
{
name:'上海11212',
py : 'shanghai'
},
{
name:'北京',
py : 'beijing'
},
{
name:'四川',
py : 'sichuan'
}
]
};
})
.controller('firstController',function($scope,Data,$filter){
$scope.data = Data;
$scope.today = new Date;
// 在控制器中使用,过滤器
var number = $filter('number')(3000);
console.log(number);
//json过滤器,主要用途是方便调试,看起来代码更加清楚
var jsonString = $filter('json')($scope.data);
console.log(jsonString);
console.log($scope.data);
//自动义过滤器,自定义一个方法解决过滤问题
$scope.checkName = function(obj){
if(obj.py.indexOf('h') === -1)
return false;
return true;
}
})
018~019 - 练习 过滤器 产品列表
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="../../vendor/bootstrap3/css/bootstrap.min.css"/>
<style>
.orderColor{
color:red;
}
</style>
</head>
<body>
<div ng-app="product">
<div class="container" ng-controller="productController">
<nav class="navbar navbar-default" role="navigation">
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" ng-model="search.id" class="form-control" placeholder="Search">
</div>
</form>
</div>
</nav>
<table class="table">
<thead>
<tr>
<th ng-click="changeOrder('id')" ng-class="{dropup:order === ''}">
产品编号
<span ng-class="{orderColor:orderType === 'id'}" class="caret"></span>
</th>
<th ng-click="changeOrder('name')" ng-class="{dropup:order === ''}">
产品名称
<span ng-class="{orderColor:orderType === 'name'}" class="caret"></span>
</th>
<th ng-click="changeOrder('price')" ng-class="{dropup:order === ''}">
产品价钱
<span ng-class="{orderColor:orderType === 'price'}" class="caret"></span>
</th>
</tr>
</thead>
<tbody>
<!--filter:{id:search} 【order + orderType= -id、id …… 】-->
<tr ng-repeat="product in productData | filter:search | orderBy:order + orderType">
<td>
{{product.id}}
</td>
<td>
{{product.name}}
</td>
<td>
{{product.price | currency : '(RMB)'}}
</td>
</tr>
</tbody>
</table>
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
angular.module('product', [])
.service('productData', function () {
return [
{
id:3333,
name:'iphone',
price : 5400
},
{
id:885,
name:'ipad',
price : 3420
},
{
id:980,
name:'imac',
price : 15400
},
{
id:1212,
name:'ipad air',
price : 2340
},
{
id:3424,
name:'ipad mini',
price : 2200
}
];
})
.controller('productController', function ($scope,productData) {
$scope.productData = productData;
$scope.orderType = 'id';
$scope.order = '-';
$scope.changeOrder = function(type){
$scope.orderType = type;
if($scope.order === ''){
$scope.order = '-';
}else{
$scope.order = '';
}
}
});
自定义过滤器
- module.filter(name, filterFactory)
- @$filterProvider.register().
020-自定义过滤器、$controllerProvider使用
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp">
<div ng-controller="firstController">
<ul>
<li ng-repeat="user in data | filterAge">
{{user.name}}
{{user.age}}
{{user.city}}
</li>
</ul>
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
var myApp = angular.module('myApp', [], function ($filterProvider, $provide, $controllerProvider) {
$provide.service('Data', function () {
return [
{
name: '张三',
age: '20',
city: '上海'
},
{
name: '李四',
age: '30',
city: '北京'
}
];
});
//第一种实现自定义过滤器的方法。
$filterProvider.register('filterAge', function () {
return function (obj) {
var newObj = [];
angular.forEach(obj, function (o) {
if (o.age > 20) {
newObj.push(o);
}
});
return newObj;
}
});
$controllerProvider.register('firstController', function ($scope, Data) {
$scope.data = Data;
})
})
//第二种实现自定义过滤器的方法,是使用模块的快捷方法实现自定义过滤器module.filter
.filter('filterCity',function(){
return function(obj){
var newObj = [];
angular.forEach(obj, function (o) {
if (o.city === '上海') {
newObj.push(o);
}
});
return newObj;
}
})
Controllers
angular controller
- 在angular中,controller是一个javascript 函数(type/class),被用作扩展除了root scope在外的angular scope的实例。
- 也可以通过module.controller(name, constructor)
- @see $controllerProvider.register().
- controller可以用作:
设置scope对象的初始状态。
增加行为到scope中。
正确的使用controller
- controller不应该尝试做太多的事情。它应该仅仅包含单个视图所需要的业务逻辑
- 保持Controller的简单性,常见办法是抽出那些不属于controller的工作到service中,在controller通过依赖注入来使用这些service
不要在Controller中做以下的事情:
- 1.任何类型的DOM操作, controller应该仅仅包含业务逻辑,任何表现逻辑放到controller中,大大地影响了应用逻辑的可测试性。angular为了自动操作(更新)DOM,提供的数据绑定。如果希望执行我们自定义的DOM操作,可以把表现逻辑抽取到directive(指令)中。
- 2.Input formatting(输入格式化) - 使用angular form controls 代替。
- 3.Output filtering (输出格式化过滤) - 使用angular filters 代替。【输出格式化过滤使用filters】
- 4.执行无状态或有状态的、controller共享的代码 - 使用angular services 代替。
- 5.实例化或者管理其他组件的生命周期(例如创建一个服务实例)。【在模块中处理】
哪些事情在controller中做
- 定义scope 中的数据,定义当前作用域中的数据
- 定义方法,如:购物车中 的例子
021-控制器的合理使用、显示和隐示的依赖注入
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp">
<div ng-controller="secondController">
</div>
<div ng-controller="otherController">
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
var myApp = angular.module('myApp', [], ['$filterProvider', '$provide', '$controllerProvider', function (a, b, c) {
console.log(a, b, c);
}])
.factory('CustomService', ['$window', function (a) {
console.log(a);
}])
// 隐示的依赖注入,js压缩,替换function中的参数,可能会出问题,不推荐这种写法。
.controller('firstController', function ($scope, CustomService) {
console.log(CustomService);
})
// 显示的依赖注入; 推荐这种写法,写在[] 里面
.controller('secondController', ['$scope', '$filter', function (a, b) {
console.log(b('json')([1, 2, 3, 4, 5]));
}]);
//这种写法不推荐
function otherController(a) {
console.log(a);
}
otherController.$inject = ['$scope'];
Directive
什么是指令
- 可以利用指令来扩展HTML标签,增加声明式语法来实现想做的任何事,可以对应用有特殊意义的元素和属性来替换一般的HTML标签
- angular也内置了非常多的指令,ng-app、ng-controller
指令和HTML校验
- angular 内置指令的语法,以ng开始,代表angular命名空间,连接符后面的内容代表指令的名称
- 指令的语法在很多HTML校验规则中是不合法的,Angular提供了多种调用指令方法,可以顺利通过不同校验的规则
校验器 | 格式 | 示例 |
none | namespace-name | ng-bind |
XML | namespace:name | ng:bind |
HTML5 | data-namespace-name | data-ng-bind |
XHTML | x-namespace-name | x-ng-bind |
ng-bind这个指令有四种写法
指令的执行过程
- 浏览器得到 HTML 字符串内容,解析得到 DOM 结构。
- ng 引入,把 DOM 结构扔给 $compile 函数处理:
- 找出 DOM 结构中有变量占位符
- 匹配找出 DOM 中包含的所有指令引用
- 把指令关联到 DOM
- 关联到 DOM 的多个指令按权重排列
- 执行指令中的 compile 函数(改变 DOM 结构,返回 link 函数)
- 得到的所有 link 函数组成一个列表作为 $compile 函数的返回
- 执行 link 函数(连接模板的 scope)。
Angular 内置指令
渲染指令
- ng-init:【初始化数据】
- ng-bind:【<p ng-bind="1+1"></p> 替换 <p>{{1+1}}</p> 这种写法】
- ng-repeat
$index 当前索引【0,1,2, 之类的数字】
$first 是否为头元素 【true、false 布尔值】
$middle 是否为非头非尾元素
$last 是否为尾元素 - ng-include 【加载另一个页面】
- ng-bind-template:【可以自定义模板<p ng-bind-template="{{1+1}}"></p>】
事件指令
内置事件指令的好处是:在处理完事件之后,帮你去自动的去实现脏检查()
- ng-change
- ng-click
- ng-dblclick
- ng-mousedown
- ng-mouseenter
- ng-mouseleave
- ng-mousemove
- ng-mouseover
- ng-mouseup
- ng-submit
节点指令
- ng-style
- ng-class
- ng-class-even、ng-class-odd【用在指令ng-repeat 里面的,奇数的时候用什么class,偶数的时候用什么class】
- ng-show
- ng-hide
- ng-switch:开关
- ng-src :和ng-bind的原理类似,都是延迟加载
- ng-href
- ng-if: 如果条件为true,就显示if 下面的内容
Demo 022~024-内置指令
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.red{
color:red;
}
</style>
</head>
<body>
<div ng-app="myApp">
<div ng-controller="firstController">
<p>{{1+1}}</p>
<p ng-bind="1+1">2</p>
<p ng-bind-template="{{1+1}}"></p>
<!-- $scope.cityArr = ['上海','北京','杭州'] -->
<ul ng-class="{red:status}" ng-init="cityArr = ['上海','北京','杭州']">
<li ng-class-even="'偶数'" ng-class-odd="'奇数'" ng-repeat="city in cityArr" >
<span>
index:{{$index}}
</span>
<span>
first:{{$first}}
</span>
<span>
middle:{{$middle}}
</span>
<span>
last :{{$last}}
</span>
<span>
{{city}}
</span>
</li>
</ul>
<div ng-include="'other.html'">
</div>
<div ng-include src="'other.html'">
</div>
<button ng-click="changeStatus($event)">点击切换</button>
<p>{{status}}</p>
<div ng-style="{color:'red'}" ng-hide="status">
你好!!!
</div>
<div ng-style="{color:'red'}" ng-show="status">
你好!!!
</div>
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
var myApp = angular.module('myApp', [])
.controller('firstController', function ($scope) {
$scope.status = false;
$scope.changeStatus = function (event) {
// 通过element转换成 jquery对象;【angularJs中提供了一些简单的jquery方法】
angular.element(event.target).html('切换状态为:' + $scope.status);
$scope.status = !$scope.status;
}
$scope.defaultStyle = {
color: 'red',
'margin-top': '50px'
};
$scope.src = 'http://www.angularjs.org/img/AngularJS-large.png';
})
Angular 自定义指令
指令的定义
- module.directive(name, directiveFactory)
- @see $compileProvider.directive()
指令的名字
- 请不要使用ng为指令命名,这样可能会和angular内置指令冲突
- 如果指令的名字为xxx-yyy 在设置指令的名字时应为xxxYyy 驼峰式声明法
指令定义选项
- priority
- terminal
- scope
- controller
- controllerAs
- require
- restrict
- template
- templateUrl
- replace
- transclude
- compile
- link
restrict
- restrict:指令在模版中的使用方式
- 可以4种风格任意组合,如果忽略restrict,默认为A
- 如果打算支持IE8,请使用基于属性和样式类的指令
字母 | 风格 | 示例 |
E | 元素【可以当做标签来使用】 | <my-dir></my-dir> |
C | 样式类 | <span class="my-dir: exp;"></span> |
A | 属性 | <span my-dir="exp"></span> |
M | 注释 | <!-- directive: my-dir exp --> |
template
- template:模板内容,这个内容会根据 replace 参数的设置替换节点或只替换节点内容。
replace
- replace:如果此配置为true则替换指令所在的元素,如果为false或者不指定,则把当前指令追加到所在的元素内部
- 对于restrict为元素(E)在最终效果中是多余的,所有 replace通常设置为true
Demo 025-自定义指令 restrict、template、replace属性
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp">
<custom-tags>1212</custom-tags>
<div class="custom-tags">
</div>
<div custom-tags>
</div>
<!-- directive:custom-tags -->
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
var myApp = angular.module('myApp', [], ['$compileProvider',function ($compileProvider) {
$compileProvider.directive('customTags',function(){
return {
restrict:'ECAM',
template:'<div>custom-tags-html</div>',
replace:true,
compile:function(){
console.log(1);//打印四次
}
}
});
}])
//.directive('')
templateUrl
- templateUrl:加载模版所要使用的URL
- 可以加载当前模板内对应的的text/ng-template script id
- 在使用chrome浏览器时,"同源策略"会阻止chrome从file://中加载模版,并显示一个"Access-Control-Allow-Origin" 不允许源为null , 可以把项目放在服务器上加载,或者给Chrome设置一个标志,命令为:
chrome —allow-file-access-from-files
transclude
- transclude:指令元素中的原来的子节点移动到一个新模版内部
- 当为true时,指令会删掉原来的内容,使你的模版可以用ng-transclude指令进行重新插入
Demo 026-自定义指令 templateUrl属性
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp">
<script type="text/ng-template" id="customTags2">
<div>
hello {{name}}
</div>
</script>
<div ng-controller="firstController">
<custom-tags></custom-tags>
<custom-tags2></custom-tags2>
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
var myApp = angular.module('myApp', [])
.directive('customTags', function () {
return {
restrict: 'ECAM',
templateUrl: 'tmp/other.html',//【引用其他页面,页面内容要用标签包含,不能事纯文本】
replace: true
}
})
.directive('customTags2', function () {
return {
restrict: 'ECAM',
templateUrl: 'customTags2',
replace: true
}
})
.controller('firstController', ['$scope', function ($scope) {
$scope.name = '张三';
}]);
priority && terminal
- priority:设置指令在模版中的执行顺序,顺序是相对于元素上其他执行而言,默认为0,从大到小的顺序依次执行
- 设置优先级的情况比较少,象ng-repeat,在遍历元素的过程中,需要angular先拷贝生成的模版元素,在应用其他指令,所以ng-repeat默认的priority是1000
- terminal 是否以当前指令的权重为结束界限。如果这值设置为 true ,则节点中权重小于当前指令的其它指令不会被执行。相同权重的会执行。
Demo 027-自定义指令 transclude、priority、terminal属性
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp">
<div ng-controller="firstController">
<custom-tags>原始数据</custom-tags>
<div custom-tags2 custom-tags3>
</div>
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
var myApp = angular.module('myApp', [])
.directive('customTags', function () {
return {
restrict: 'ECAM',
template:'<div>新数据 <span ng-transclude></span></div>',
replace: true,
transclude:true
}
})
.directive('customTags2', function () {
return {
restrict: 'ECAM',
template:'<div>2</div>',
replace: true,
priority:-1
}
})
.directive('customTags3', function () {
return {
restrict: 'ECAM',
template:'<div>3</div>',
replace: true,
priority: 0,
// 小于0的 directive 都不会执行
terminal:true
}
})
.controller('firstController', ['$scope', function ($scope) {
$scope.name = '张三';
}]);
Angularjs 指令编译三阶段【重点】
- 1. 标准浏览器API转化
将html转化成dom,所以自定义的html标签必须符合html的格式 - 2. Angular compile
搜索匹配directive,按照priority排序,并执行directive上的compile方法 - 3. Angular link
执行directive上的link方法,进行scope绑定及事件绑定
为什么编译的过程要分成compile和link?
- 简单的说就是为了解决性能问题,特别是那种model变化会影响dom结构变化的,而变化的结构还会有新的scope绑定及事件绑定,比如ng-repeat
compile和link的使用时机
- Compile【修改dom结构】
想在dom渲染前对它进行变形,并且不需要scope参数
想在所有相同directive里共享某些方法,这时应该定义在compile里,性能会比较好
返回值就是link的function,这时就是共同使用的时候 - Link 【绑定事件】
对特定的元素注册事件
需要用到scope参数来实现dom元素的一些行为
compile
- complie:function(tElement,tAttrs,transclude)
- complie函数用来对模版自身进行转换,仅仅在编译阶段运行一次
- complie中直接返回的函数是postLink,表示link参数需要执行的函数,也可以返回一个对象里面包含preLink和postLink
- 当定义complie参数时,将无视link参数,因为complie里返回的就是该指令需要执行的link函数
link
- link(scope,iElement,iAttrs,controller)
- link参数代表的是complie返回的postLink
- preLink 表示在编译阶段之后,指令连接到子元素之前运行
- postLink 表示会在所有子元素指令都连接之后才运行
- link函数负责在模型和视图之间进行动态关联,对于每个指令的每个实例,link函数都会执行一次
Demo 028-自定义指令 compile && link属性
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp">
<div ng-controller="firstController">
<!--
1. div 转换为dom结构
2. 默认的优先级为0,哪个先定义哪个先使用
-->
<div ng-repeat="user in users" custom-tags="" custom-tags2>
</div>
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
var i = 0;
var myApp = angular.module('myApp', [])
.directive('customTags',function(){
return {
restrict : 'ECAM',
template : '<div>{{user.name}}</div>',
replace : true,
//tElement 当前元素的 element,当前元素的jquery对象
//tAttrs 当前元素的一些属性
compile:function(tElement,tAttrs,transclude){//【有了compile之后,定义link就没有用了,因为,compile中也包含了link】
tElement.append(angular.element('<div>{{user.name}}{{user.count}}</div>'));
// 编译阶段...
console.log('customTags compile 编译阶段...');
return {
// 表示在编译阶段之后,指令连接到子元素之前运行
pre:function preLink(scope,iElement,iAttrs,controller){
console.log('customTags preLink..')
},
// 表示在所有子元素指令都连接之后才运行
post:function postLink(scope,iElement,iAttrs,controller){
iElement.on('click',function(){
scope.$apply(function(){//【apply方法触发脏检查】
scope.user.name = 'click after';
scope.user.count = ++i;
// 进行一次 脏检查
});
})
console.log('customTags all child directive link..')
}
}
// 可以直接返回 postLink
// return postLink function(){
// console.log('compile return fun');
//}
},
// 此link表示的就是 postLink【因为在 compile中已经定义了link,故而,这里没有必要再定义】
link:function(){
// iElement.on('click',function(){
// scope.$apply(function(){
// scope.user.name = 'click after';
// scope.user.count = ++i;
// // 进行一次 脏检查
// });
// })
}
}
})
.directive('customTags2',function(){
return {
restrict : 'ECAM',
replace : true,
compile:function(){
// 编译阶段...
console.log('customTags2 compile 编译阶段...');
return {
// 表示在编译阶段之后,指令连接到子元素之前运行
pre:function preLink(){
console.log('customTags2 preLink..')
},
// 表示在所有子元素指令都连接之后才运行
post:function postLink(){
console.log('customTags2 all child directive link..')
}
}
}
}
})
.directive('customTags3',function(){ // return postLink;
return function(){
}
})
.controller('firstController', ['$scope', function ($scope) {
$scope.users = [
{
id:10,
name:'张三'
},
{
id:20,
name:'李四'
}
];
}]);
controller && controllerAs && require
- controller 他会暴露一个API,利用这个API可以在多个指令之间通过依赖注入进行通信(作用)
- controller($scope,$element,$attrs,$transclude)
- controllerAs 是给controller起个别名,方便使用
- require 可以将其他指令传递给自己
选项 | 用法 |
directiveName | 通过驼峰法的命名指定了控制器应该带有哪一条指令,默认会从同一个元素上的指令 |
^directiveName | 在父级查找指令 |
?directiveName | 表示指令是可选的,如果找不到,不需要抛出异常 |
Demo 029-自定义指令 controller && controllAs属性
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp">
<div ng-controller="firstController">
<div book-list>
</div>
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
angular.module('myApp', [])
.directive('bookList', function () {
return {
restrict: 'ECAM',
controller: function ($scope) {
$scope.books = [
{
name: 'php'
},
{
name: 'javascript'
},
{
name: 'java'
}
];
$scope.addBook = function(){
}
this.addBook = function(){
// ...
}
},
controllerAs:'bookListController',//【相当于给上面的controller起一个别名,在link函数中有引用】
template: '<ul><li ng-repeat="book in books">{{book.name}}</li></ul>',
replace:true,
link:function(scope,iEelement,iAttrs,bookListController){
iEelement.on('click',bookListController.addBook)
}
}
})//【这里不要给分号,给了后面就不能.controller了,就不能链式操作了】
//不写全,代码压缩会报错
.controller('firstController', ['$scope', function ($scope) {
// console.log($scope);
}]);
Demo 030-自定义指令 require 属性
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp">
<div ng-controller="firstController">
<div book-list>
</div>
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
angular.module('myApp', [])
.directive('bookList', function () {
return {
restrict: 'ECAM',
controller: function ($scope) {
$scope.books = [
{
name: 'php'
},
{
name: 'javascript'
},
{
name: 'java'
}
];
this.addBook = function(){
$scope.$apply(function(){
$scope.books.push({
name:'Angularjs'
})
});
}
},
controllerAs:'bookListController',
template: '<div><ul><li ng-repeat="book in books">{{book.name}}</li></ul><book-add></book-add></div>',
replace:true
}
})
.directive('bookAdd',function(){
return {
restrict:'ECAM',
require:'^bookList',//【^directiveName 带有^ 符号,表示在父级查找指令】
template:'<button type="button">添加</button>',
replace:true,
link:function(scope,iElement,iAttrs,bookListController){
iElement.on('click',bookListController.addBook);
}
}
})
.controller('firstController', ['$scope', function ($scope) { // console.log($scope);
}]);
scope
- scope:为当前指令创建一个新的作用域,而不是使之继承父作用域
- false 继承父元素的作用域
true 创建一个新的作用域
object 独立的scope - object:参数
&:作用域把父作用域的属性包装成一个函数,从而以函数的方式读写父作用域的属性
=:作用域的属性与父作用域的属性进行双向绑定,任何一方的修改均影响到对方
@:只能读取父作用域里的值单项绑定【只能是简单类型,不能是引用类型的,不能是对象】
【写的多了自然而然就理解了, angularjs 难点在于指令之间的架构】
Demo 031 - 自定义指令 scope 属性
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp">
<div ng-controller="firstController">
{{
books
}}
<div book-list books="books" parent-books="books" parent-title="{{title}}">
</div>
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
angular.module('myApp', [])
.directive('bookList', function () {
return {
restrict: 'ECAM',
controller: function ($scope) {
// &books
// $scope.books = $scope.a();
//================================================================
// =books;
// $scope.books = $scope.b;
// $scope.b.push({name:'nodejs'});
//================================================================
console.log($scope.c);
},
// scope:true, 创建一个有继承链的独立作用域
/ /scope:false, 不创建作用域,继承父元素的作用域
// 当为对象的时候也会创建一个独立的作用域
scope:{
// & 将父元素 books 封装成一个a函数
// a:'&books'
//================================================================
// = 双向绑定 b = parentBooks属性对应的父作用域的表达式
// b:'=parentBooks'
//================================================================
// @ 只能引用父元素的简单类型的属性
c:'@parentTitle'
},
controllerAs:'bookListController',
template: '<div><ul><li ng-repeat="book in books">{{book.name}}</li></ul></div>',
replace:true
}
})
.controller('firstController', ['$scope', function ($scope) {
console.log($scope);
$scope.books = [
{
name: 'php'
},
{
name: 'javascript'
},
{
name: 'java'
}
];
$scope.title = '张三';
}]);
Demo 032 - 练习 自定义accordion指令 skip
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="../../vendor/bootstrap3/css/bootstrap.min.css"/>
</head>
<body>
<div ng-app="myApp">
<div class="container">
<div ng-controller="firstController">
<kittencup-group>
<kittencup-collapse ng-repeat="collapse in data" heading="{{collapse.title}}">
{{collapse.content}}
</kittencup-collapse>
</kittencup-group>
</div>
</div>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
angular.module('myApp', [])
// 数据
.factory('Data', function () {
return [
{
title: 'no1',
content: 'no1-content'
},
{
title: 'no2',
content: 'no2-content'
},
{
title: 'no3',
content: 'no3-content'
}
];
})
// 控制器
.controller('firstController', ['$scope','Data',function ($scope,Data) {
$scope.data = Data;
}])
.directive('kittencupGroup',function(){
return {
restrict:'E',
replace:true,//【该标签不符合w3c 规范,肯定要替换掉它】
template:'<div class="panel-group" ng-transclude></div>',
transclude:true,
controllerAs:'kittencupGroupContrller',
controller:function(){
this.groups = [];
this.closeOtherCollapse = function(nowScope){
angular.forEach(this.groups,function(scope){
if(scope !== nowScope){
scope.isOpen = false;
}
})
}
}
}
})
.directive('kittencupCollapse',function(){
return {
restrict:'E',
replace:true,
require:'^kittencupGroup',
templateUrl:'app/tmp/kittencupCollapse.html',//【因为,模板代码比较长,故而,用另外一个页面】
scope:{
heading:'@'
},
link:function(scope,element,attrs,kittencupGroupContrller){
scope.isOpen = false;
scope.changeOpen = function(){
scope.isOpen = !scope.isOpen;
kittencupGroupContrller.closeOtherCollapse(scope);
}
kittencupGroupContrller.groups.push(scope);
},
transclude:true
}
})
<div class="panel panel-default">
<div class="panel-heading" ng-click="changeOpen()">
<h4 class="panel-title">
<a href="#">
{{heading}}
</a>
</h4>
</div>
<div class="panel-collapse" ng-class="{collapse:!isOpen}">
<div class="panel-body" ng-transclude>
</div>
</div>
</div>
Module里的一些其他方法
constant
- constant(name,object)
- 此方法首先运行,可以用它来声明整个应用范围内的常量,并且让它们在所有配置(config方法里)和实例(controller,service等)方法中都可用
value
- value(name,object)
- 如果只想在服务内得到一些内容,可以通过value来申明常量
run
- run(initializationFn)
- 想要在注入启动之后执行某些操作,而这些操作需要在页面对用户可用之前执行,可以使用此方法
- 比如加载远程的模版,需要在使用前放入缓存,或者在使用操作前判断用户是否登录,未登录可以先去登陆页面
Demo 033 - 模块里的constant、value、run方法
angular.module('myApp',[],['$provide',function($provide){
console.log('config');
// $provide.factory
// $provide.service
// $provide.constant
// $provide.value;//【provide中的方法 都会有快捷方法】
}])
.config(function(APIKEY){
console.log(APIKEY);
console.log('config');
})
// 在config之后controller等其他服务之前,执行此方法。。
.run(function(){
console.log('run');
})
// 它只是可以注入任何方法
.constant('APIKEY','xxxx')
// 只能注入controller...service factory。【在config中无法注入该方法】
.value('vension','1.0.0')
.controller('firstController',['APIKEY','vension',function(APIKEY,vension){
console.log(APIKEY);
console.log(vension);
console.log('controller');
}]);
Form表单
- 一般来讲表单可能遇到的问题
1.如何数据绑定
2.验证表单
3.显示出错信息
4.整个Form的验证
5.避免提交没有验证通过的表单
7.防止多次提交
input type 扩展
- number
- url
- reset
input 属性
- name 名字
- ng-model 绑定的数据
ng-model="data.username" 数据绑定在data.username上
- ng-required 是否必填
ng-required="true" 值为true 表示必填项
- ng-minlength 最小长度
- ng-maxlength 最大长度
- ng-pattern 匹配模式
- ng-change 值变化时的回调
CSS样式
- ng-valid 当表单验证通过时的设置
- ng-invalid 表单验证失败时的设置
- ng-pristine 表单的未被动之前拥有
- ng-dirty 表单被动过之后拥有
Form控制变量
- 字段是否未更改
formName.inputFieldName.$pristine - 字段是否更改
formName.inputFieldName.$dirty - 字段有效
formName.inputFieldName.$valid - 字段无效
formName.inputFieldName.$invalid当表单的字段无效,该字段为true
- 字段错误信息
formName.inputfieldName.$errorForm名字. 表单名字 获取表单的错误信息
属性 | 描述 |
$dirty | 表单有填写记录 |
$valid | 字段内容合法的 |
$invalid | 字段内容是非法的 |
$pristine | 表单没有填写记录 |
From 方法
- $setPristine 将表单复位原始状态,class,$dirty,$pristine
ng-model
- ng-model是angular原生的directive
- 可以通过require ngModel 可以更深入的去处理数据的双向绑定
ngModel 里的属性
- $parsers属性 保存了从viewValue向modelValue绑定过程中的处理函数,它们将来会依次执行
- $formatters 它保存的是从modelValue向viewValue绑定过程中的处理函数
- $setViewValue 当view发生了某件事情时,从view向model绑定调用$setViewValue 把viewValue保存下来
- $render 当模型发生变化时,应该怎么去更新视图,从model向view绑定,调用ctrl.$render方法,将viewValue渲染到页面上
- $setValidity 设置验证结果
- $viewValue 视图的值
- $modelValue 模型里的值
XHR和服务器端的通信
$http
- $http 是一个服务,简单的封装了XMLHttpRequest对象
- $http(config).success(fun).error(fun)
$http短名方法
- $http.get()
- $http.delete()
- $http.header()
- $http.jsonp()
- $http.post()
- $http.put()
$http 配置对象
- method
- url
- params
- data
- headers
- xsrfHeaderName
- xsrfCookieName
- transformRequest
- transformResponse
- cache
- withCredentials
- timeout
- responseType
responseType
- " (string – default)
- "arraybuffer" (ArrayBuffer)
- "blob" (blob object)
- "document" (HTTP document)
- "json" (JSON object parsed from a JSON string)
- "text" (string)
- "moz-blob" (Firefox to receive progress events)
- "moz-chunked-text" (streaming text)
- "moz-chunked-arraybuffer" (streaming ArrayBuffer)
Demo 034-Form
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="../../vendor/bootstrap3/css/bootstrap.min.css"/>
</head>
<body>
<div ng-app="myApp" style="margin-top: 100px;">
<form name="myForm" action="kittencup.php" ng-controller="firstController" class="container form-horizontal">
<div class="form-group" ng-class="{'has-error':myForm.username.$dirty && myForm.username.$invalid}">
<label class="col-sm-2 control-label">用户名</label>
<div class="col-sm-10">
<input type="text" autocomplete="off" name="username" ng-pattern="/^[a-zA-Z]{1}/" ng-required="true" ng-minlength="5" ng-maxlength="10" ng-model="data.username" class="form-control" placeholder="用户名">
<div ng-show="myForm.username.$dirty && myForm.username.$error.maxlength" class="alert alert-danger help-block">
用户名长度不能超过10位
</div>
<div ng-show="myForm.username.$dirty && myForm.username.$error.minlength" class="alert alert-danger help-block">
用户名长度不能小于5位
</div>
<div ng-show="myForm.username.$dirty && myForm.username.$error.pattern" class="alert alert-danger help-block">
用户名必须已英文字母开始
</div>
</div>
</div>
<div class="form-group" ng-class="{'has-error':myForm.password.$dirty && myForm.password.$invalid}">
<label class="col-sm-2 control-label">密 码</label>
<div class="col-sm-10">
<input type="password" autocomplete="off" name="password" ng-required="true" ng-minlength="5" ng-maxlength="10" ng-model="data.password" class="form-control" placeholder="密码">
<div ng-show="myForm.password.$dirty && myForm.password.$error.maxlength" class="alert alert-danger help-block">
密码长度不能超过10位
</div>
<div ng-show="myForm.password.$dirty && myForm.password.$error.minlength" class="alert alert-danger help-block">
密码长度不能小于5位
</div>
</div>
</div>
<div class="form-group" ng-class="{'has-error':myForm.passwordConfirm.$dirty && myForm.passwordConfirm.$invalid}">
<label class="col-sm-2 control-label">确认密码</label>
<div class="col-sm-10">
<input type="password" autocomplete="off" name="passwordConfirm" ng-required="true" ng-model="data.passwordConfirm" class="form-control" placeholder="确认密码">
<div ng-show="myForm.password.$dirty && myForm.passwordConfirm.$dirty && data.password !== data.passwordConfirm" class="alert alert-danger help-block">
密码和确认密码不一致
</div>
</div>
</div>
<div class="form-group" ng-class="{'has-error':myForm.email.$dirty && myForm.email.$invalid}">
<label class="col-sm-2 control-label">邮箱</label>
<div class="col-sm-10">
<input type="email" autocomplete="off" name="email" ng-required="true" ng-minlength="5" ng-maxlength="30" ng-model="data.email" class="form-control" placeholder="邮箱">
<div ng-show="myForm.email.$dirty && myForm.email.$error.maxlength" class="alert alert-danger help-block">
邮箱长度不能超过30位
</div>
<div ng-show="myForm.email.$dirty && myForm.email.$error.minlength" class="alert alert-danger help-block">
邮箱长度不能小于5位
</div>
<div ng-show="myForm.email.$dirty && myForm.email.$error.email" class="alert alert-danger help-block">
邮箱格式不正确
</div>
</div>
</div>
<div class="form-group" ng-class="{'has-error':myForm.blog.$dirty && myForm.blog.$invalid}">
<label class="col-sm-2 control-label">博客网址</label>
<div class="col-sm-10">
<input type="url" autocomplete="off" name="blog" ng-required="true" ng-minlength="5" ng-maxlength="30" ng-model="data.blog" class="form-control" placeholder="博客网址">
<div ng-show="myForm.blog.$dirty && myForm.blog.$error.maxlength" class="alert alert-danger help-block">
网址长度不能超过30位
</div>
<div ng-show="myForm.blog.$dirty && myForm.blog.$error.minlength" class="alert alert-danger help-block">
网址长度不能小于5位
</div>
<div ng-show="myForm.blog.$dirty && myForm.blog.$error.url" class="alert alert-danger help-block">
网址格式不正确
</div>
</div>
</div>
<div class="form-group" ng-class="{'has-error':myForm.age.$dirty && myForm.age.$invalid}">
<label class="col-sm-2 control-label">年龄</label>
<div class="col-sm-10">
<input type="number" autocomplete="off" name="age" min="10" max="99" ng-required="true" ng-model="data.age" class="form-control" placeholder="年龄">
<div ng-show="myForm.age.$dirty && myForm.age.$error.max" class="alert alert-danger help-block">
年龄不能超过99岁
</div>
<div ng-show="myForm.age.$dirty && myForm.age.$error.min" class="alert alert-danger help-block">
年龄不能小于10岁
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">性别</label>
<div class="col-sm-10">
<label class="radio-inline">
<input type="radio" ng-required="true" name="sex" ng-model="data.sex" value="1" /> 男
</label>
<label class="radio-inline">
<input type="radio" ng-required="true" name="sex" ng-model="data.sex" value="0" /> 女
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">爱好</label>
<div class="col-sm-10">
<label class="checkbox-inline" ng-repeat="hobby in hobbies">
<input type="checkbox" ng-model="hobby.checked" name="hobby[]" ng-checked="data.hobbies === undefined ? false : data.hobbies.indexOf(hobby.id) !== -1" ng-click="toggleHobbySelection(hobby.id)"/> {{hobby.name}}
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">出生地</label>
<div class="col-sm-3">
<select class="form-control" ng-change="data.area = false" ng-model="data.province" ng-options="x.id as x.name for x in cities | cityFilter:0"></select>
</div>
<div class="col-sm-3">
<select class="form-control" ng-show="data.province" ng-model="data.area" ng-options="x.id as x.name for x in cities | cityFilter:data.province"></select>
</div>
<div class="col-sm-3">
<select class="form-control" ng-required="true" ng-show="data.province && data.area" ng-model="data.city" ng-options="x.id as x.name for x in cities | cityFilter:data.area"></select>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">只能输入偶数</label>
<div class="col-sm-10">
<input type="text" name="even" class="form-group" placeholder="偶数" ng-model="data.even" even>
<div ng-show="myForm.even.$error.even" class="alert alert-danger help-block">
数字必须是偶数
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">个人介绍</label>
<div class="col-sm-10">
<custom-text-area ng-model="data.introduct">aaa</custom-text-area>
<custom-text-area ng-model="data.introduct"></custom-text-area>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default" ng-disabled="myForm.$invalid || data.hobbies === undefined || data.hobbies.length === 0">注册</button>
<button type="reset" class="btn btn-default" ng-click="reset()">重置</button>
</div>
</div>
</form>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>
angular.module('myApp', [])
.filter('cityFilter', function () {
return function (data, parent) {
var filterData = [];
angular.forEach(data, function (obj) {
if (obj.parent === parent) {
filterData.push(obj);
}
})
return filterData;
}
})
.directive('even',function(){
return {
require : 'ngModel',
link:function(scope,elm,attrs,ngModelController){
ngModelController.$parsers.push(function(viewValue){
if(viewValue % 2 === 0){
ngModelController.$setValidity('even',true);
}else{
ngModelController.$setValidity('even',false);
}
return viewValue;
});
// ngModelController.$formatters.push(function(modelValue){
// return modelValue + 'kittencup';
// })
}
};
})
.directive('customTextArea',function(){
return {
restrict:'E',
template:'<div contenteditable="true"></div>',
replace:true,
require : 'ngModel',
link:function(scope,elm,attrs,ngModelController){
// view->model
elm.on('keyup',function(){
scope.$apply(function(){
ngModelController.$setViewValue(elm.html());
});
})
ngModelController.$render = function(){
elm.html(ngModelController.$viewValue);
}
}
};
})
.controller('firstController', ['$scope', function ($scope) {
var that = this;
$scope.hobbies = [
{
id: 1,
name: '玩游戏'
},
{
id: 2,
name: '写代码'
},
{
id: 3,
name: '睡觉'
},
];
$scope.cities = [
{
name: '上海',
parent: 0,
id: 1
},
{
name: '上海市',
parent: 1,
id: 2
},
{
name: '徐汇区',
parent: 2,
id: 8
},
{
name: '长宁区',
parent: 2,
id: 3
},
{
name: '北京',
parent: 0,
id: 4
},
{
name: '北京市',
parent: 4,
id: 5
},
{
name: '东城区',
parent: 5,
id: 6
},
{
name: '丰台区',
parent: 5,
id: 7
},
{
name: '浙江',
parent: 0,
id: 9
},
{
name: '杭州',
parent: 9,
id: 100
},
{
name: '宁波',
parent: 9,
id: 11
},
{
name: '西湖区',
parent: 100,
id: 12
},
{
name: '北仑区',
parent: 11,
id: 13
}
];
$scope.data = {
hobbies: [1, 2],
city: 3
};
// 先保留一份默认值
$scope.origData = angular.copy($scope.data);
$scope.reset = function(){
$scope.data = angular.copy($scope.origData);
that.initCity();
$scope.myForm.$setPristine();
}
// 让城市关联使用
this.findCityId = function (parent) {
var parentId;
angular.forEach($scope.cities, function (city) {
if (city.id === parent) {
parentId = city.parent;
return;
}
})
return parentId;
}
this.initCity = function(){
if ($scope.data.city !== undefined) {
$scope.data.area = this.findCityId($scope.data.city);
$scope.data.province = this.findCityId($scope.data.area);
}
}
// 第一次打开页面 需要初始化一下
this.initCity.call(this);
$scope.toggleHobbySelection = function (id) {
var index = -1;
if ($scope.data.hobbies === undefined) {
$scope.data.hobbies = [];
} else {
index = $scope.data.hobbies.indexOf(id);
}
if (index === -1) {
$scope.data.hobbies.push(id);
} else {
$scope.data.hobbies.splice(index, 1);
}
}
}]);
路由
使用AngularUI库 实现路由
AngularUI库提供的最有用的库之一便是ui-router。它是一个路由框架,允许你通过状态机
组织接口,而不是简单的URL路由。
你还要确保在视图中链接这个库:
<scripttype="text/javascript" src="app/bower_components/angular-ui-router/release/angular-ui-router.js"></script>
同时还需要将ui.router作为依赖注入到你的应用中:
angular.module('myApp', ['ui.router']);
现在,不同于内置的ngRoute服务,由于ui-router基于状态工作,而不是简单的url,因此
你可以将它嵌套在视图中。
在处理ngRoute服务时我们不再使用ng-view,而改为使用ui-view指令。
在ui-router内处理路由和状态时,我们主要关心的是应用程序处在哪个状态以及Web应用
当前处在哪个路由位置。
<div ng-controller="DemoController">
<div ui-view></div>
</div>
和ngRoute一样,定义在任意给定状态内的模板都处在<div ui-view></div>元素内。此外,
每个模板都可以包含自己的ui-view。 这事实上就允许你在路由中嵌套视图。
为了定义路由,你可以使用.config方法,和常见的方式一样,但不是将路由设置在
$routeProvider上,而是将状态设置在$stateProvider上。
.config(function($stateProvider,$urlRouterProvider) {
$stateProvider
.state('start', {
url: '/start',
templateUrl: 'partials/start.html'
})
});
这一步给状态配置对象分配了一个名为start的状态。这个状态配置对象,或者说这个
stateConfig
stateProvider
.state('inbox', {
url: '/inbox',
template: '<h1>Welcome to your inbox</h1>'
});
当用户导航到/inbox时,应用会转换到inbox状态,然后使用模板内容(<h1>Welcome to your
inbox</h1>)填充主要的ui-view指令。
//当用户导航到url:/main时,使用templateUrl填充ui-view指令。
.state('main', {
url: '/main',
controller: "HeaderCtrl",
templateUrl: 'views/main.html'
})
2. controller
和ngRoute一样,你可以给已经注册好的控制器关联一个URL(使用字符串),也可以创建一
个控制器函数作为状态控制器。
如果没有定义模板(使用上述方式之一),就不会创建这个控制器。
3.URL
URL可以接受一系列不同的选项,它还可以在url中设置基本的参数,就像在ngRoute中一样:
$stateProvider
.state('inbox', {
url: '/inbox/:inboxId',
template: '<h1>Welcome to your inbox</h1>',
controller: function($scope, $stateParams) {
$scope.inboxId = $stateParams.inboxId;
}
});
参考
AngularJs 权威教程 第25章