@octopus
2016-09-14T18:26:10.000000Z
字数 16460
阅读 1293
angular.js
- 此笔记为观看油管大神 @kudvenkat 视频的学习中所做笔记 YouTube视频链接
- 同时借鉴《AngularJS权威教程》一书整理相关概念
官方定义:
一个应用可以包含多个模块,每一个模块都包含了定义具体功能的代码。
我们使用 angular.module()方法来声明模块,这个方法能够接受两个参数,第一个是模块的名称,第二个是依赖列表,也就是可以被注入到模块中的对象列表。
简而言之:
- 模块就是为了不污染全局空间自定义的作用域,在作用域内控制器的一系列操作才会生效。
<html ng-app="myApp"> // 在html代码中定义模块的作用范围
...
</html>
<script>
var myapp = angular.module('myApp', []); // 声明模块
</script>
官方:
- 控制器是一个函数,用来向视图的作用域中添加额外的功能。我们用它来给作用域对象设置初始状态,并添加自定义行为。
简而言之:
- 控制器可以定义作用域对象,定义方法,来为前台提供有效数据、响应事件。
<div ng-controller="FirstController">
...
</div>
<script>
var app = angular.module('app', []);
app.controller('FirstController', function($scope) {
$scope.message = "hello";
});
</script>
官方:
$scope对象是定义应用业务逻辑、控制器方法和视图属性的地方。作用域是视图和控制器之间的胶水。
作用域是应用状态的基础。基于动态绑定,我们可以依赖视图在修改数据时立刻更新 $scope,也可以依赖 $scope在其发生变化时立刻重新渲染视图,有监视数据模型变化的能力。
当需要动态绑定src路径时,一定要用 ng-src
指令,用原始 src
浏览器加载时会把ng的变量名当做路径先加载,导致一个资源未找到的错误,然后ng再解析包含路径对应的资源。
<img src="{{src}}" alt="Description" /> // bug
<img ng-src="{{src}}" alt="Description" /> // 正确
<script>
var app = angular.module('app', []);
app.controller('xxController', function($scope) {
$scope.src = "www.baidu.com";
});
</script>
<div ng-controller="myController">
<table>
<tr>
<th>number</th>
<th>name</th>
<th>age</th>
<th>city</th>
</tr>
<tr ng-repeat="employee in employees">
<td>{{ $index }}</td>
<td>{{ employee.name }}</td>
<td>{{ employee.age }}</td>
<td>{{ employee.city }}</td>
</tr>
</table>
</div>
<script>
var myapp = angular.module("myApp", [])
myapp.controller("myController", function($scope) {
var employees = [
{name:"zhang",age:18,city:"shandong"},
{name:"lisi",age:20,city:"jinan"},
{name:"wangwu",age:27,city:"shanghai"},
];
$scope.employees = employees;
});
</script>
其中,
$index
与$parent.$index
可以获取当前迭代号与父节点的迭代号
ng-hide=true 隐藏
ng-hide=false 显示
<div ng-controller="myController">
· hide? <input type="checkbox" ng-model="hideSalary" /> // 页面初次载入时此并未定义,undefind,所以等同于false
<table class="table table-bordered">
<tr class="danger">
<th>name</th>
<th>city</th>
<th ng-hide="hideSalary">salary</th>
</tr>
<tr ng-repeat="people in peoples">
<td>{{ people.name }}</td>
<td>{{ people.city }}</td>
<td ng-hide="hideSalary">{{ people.salary }}</td>
</tr>
</table>
</div>
<script>
angular.module("myApp", [])
.controller("myController", function($scope) {
var peoples = [
{name:"zhangyu",city:"jinan",salary:55000},
{name:"wangwu",city:"beijing",salary:35600},
{name:"lisi",city:"shanghai",salary:2100},
{name:"wanger",city:"shenzhen",salary:61000}
];
$scope.peoples = peoples;
});
</script>
ng-show=true 显示
ng-show=false 隐藏
ng-init 定义作用域的属性,但尽可能的把控制器能做的交给控制器去做
<ul>
<li ng-repeat="people in peoples" ng-init="parentIndex = $index">
{{$index}}
<ul>
<li ng-repeat="thing in people.something">
{{parentIndex}}
</li>
</ul>
</li>
</ul>
包含其他 HTML 文件,但经测试只在有 firfox 有效,chrome 无效
<div ng-controller="myController">
<select ng-model="selectPage">
<option value="index2.html">index2.html</option>
<option value="index3.html">index3.html</option>
</select>
<div ng-include="selectPage"></div>
</div>
<script>
angular.module("myApp", [])
.controller("myController", function($scope) {
$scope.selectPage = "index2.html";
});
</script>
<div ng-controller="myController">
<table>
<tr>
<th>technolog</th>
<th>like</th>
<th>dislike</th>
<th>like/dislike btn</th>
</tr>
<tr ng-repeat="technolog in technologies">
<td>{{ technolog.name }}</td>
<td>{{ technolog.likes }}</td>
<td>{{ technolog.dislikes }}</td>
<td>
<input type="button" value="like" ng-click="likes(technolog)">
<input type="button" value="dislike" ng-click="dislikes(technolog)">
</td>
</tr>
</table>
</div>
<script>
angular.module("myApp", [])
.controller("myController", function($scope) {
var technologies = [
{name:"php",likes:0,dislikes:0},
{name:"java",likes:0,dislikes:0},
{name:"c#",likes:0,dislikes:0},
{name:"c++",likes:0,dislikes:0},
{name:"angularjs",likes:0,dislikes:0}
];
$scope.technologies = technologies;
$scope.likes = function(technologies){
technologies.likes++;
};
$scope.dislikes = function(technologies){
technologies.dislikes++;
};
});
</script>
filter 有三种作用:1. 格式化 2. 排序 3. 过滤
基本格式:{{ expression | filterName:parameter }}
{{ "ZHANG" | lowercase }} // zhang
{{ "zhang" | uppercase }} // ZHANG
{{ 5320000.225 | number:2 }} // 5,320,000.22 (保留两位小数)
{{ date | date:"dd-MM-yyyy" }} // 08-09-2016 ( $scope.date = new Date(); )
格式:
{{ expression | orderBy:"+age" }}
表示对age升序排序,同理 "-age" 表示降序排序,默认为升序
<div ng-controller="myController">
order by:
<select ng-model="sort"> // *
<option value="+name">name - ASC</option>
<option value="+salary">salary - ASC</option>
<option value="-name">name - DESC</option>
<option value="-salary">salary - DESC</option>
</select>
<table class="table table-bordered">
<tr class="danger">
<th>name</th>
<th>salary</th>
</tr>
<tr ng-repeat="people in peoples | orderBy:sort">
<td>{{ people.name }}</td>
<td>{{ people.salary }}</td>
</tr>
</table>
</div>
<script>
angular.module("myApp", [])
.controller("myController", function($scope) {
var peoples = [
{name:"zhangyu",salary:55000},
{name:"wangyu",salary:35600},
{name:"lisi",salary:2100},
{name:"wanger",salary:61000}
];
$scope.peoples = peoples;
$scope.sort = "name"; // *
});
</script>
充分利用动态数据绑定,更新排序字段与排序方式
<div ng-controller="myController">
<table class="table table-bordered">
<tr class="danger">
<th ng-click="sortData('name')">name <div ng-class="getSortClass('name')"></div></th>
<th ng-click="sortData('salary')">salary <div ng-class="getSortClass('salary')"></div></th>
</tr>
<tr ng-repeat="people in peoples | orderBy:sort:reverseSort"> // * reverseSort 为 true 则正序排序,false 为倒序排序
<td>{{ people.name }}</td>
<td>{{ people.salary }}</td>
</tr>
</table>
</div>
<script>
angular.module("myApp", [])
.controller("myController", function($scope) {
var peoples = [
{name:"zhangyu",salary:55000},
{name:"wangyu",salary:35600},
{name:"lisi",salary:2100},
{name:"wanger",salary:61000}
];
$scope.peoples = peoples;
$scope.sort = "name";
$scope.reverseSort = false;
$scope.sortData = function(column){
$scope.reverseSort = ($scope.sort == column)? !$scope.reverseSort : false;
$scope.sort = column;
};
$scope.getSortClass = function(column){
if ($scope.sort == column){
return $scope.reverseSort ? 'arrow-down':'arrow-up';
}
return '';
};
});
</script>
// css 样式
.arrow-up{
width:0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 5px solid black;
float: right;
margin-top: 8px;
}
.arrow-down{
width:0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid black;
float: right;
margin-top: 8px;
}
<div ng-controller="myController">
显示行数:<input type="number" ng-model="limit" /> // *
<br>
<br>
<table class="table table-bordered">
<tr class="danger">
<th>technolog</th>
<th>like</th>
<th>dislike</th>
<th>like/dislike btn</th>
</tr>
<tr ng-repeat="technolog in technologies | limitTo:limit"> // *
<td>{{ technolog.name }}</td>
<td>{{ technolog.likes }}</td>
<td>{{ technolog.dislikes }}</td>
<td>
<input type="button" value="like" ng-click="likes(technolog)">
<input type="button" value="dislike" ng-click="dislikes(technolog)">
</td>
</tr>
</table>
</div>
<script>
angular.module("myApp", [])
.controller("myController", function($scope) {
var technologies = [
{name:"php",likes:0,dislikes:0},
{name:"java",likes:0,dislikes:0},
{name:"c#",likes:0,dislikes:0},
{name:"c++",likes:0,dislikes:0},
{name:"angularjs",likes:0,dislikes:0}
];
$scope.technologies = technologies;
$scope.likes = function(technologies){
technologies.likes++;
};
$scope.dislikes = function(technologies){
technologies.dislikes++;
};
$scope.limit = 3; // *
});
</script>
卧槽超级简单啊,相关代码只有两句话!关键语句:<tr ng-repeat="people in peoples | filter:filterName">
<div ng-controller="myController">
Search: <input type="text" ng-model="searchText"> // *
<table class="table table-bordered">
<tr class="danger">
<th>name</th>
<th>salary</th>
</tr>
<tr ng-repeat="people in peoples | filter:searchText"> // *
<td>{{ people.name }}</td>
<td>{{ people.salary }}</td>
</tr>
</table>
</div>
<script>
angular.module("myApp", [])
.controller("myController", function($scope) {
var peoples = [
{name:"zhangyu",salary:55000},
{name:"wangwu",salary:35600},
{name:"lisi",salary:2100},
{name:"wanger",salary:61000}
];
$scope.peoples = peoples;
});
</script>
<div ng-controller="myController">
Search name: <input type="text" ng-model="searchText.name">
Search city: <input type="text" ng-model="searchText.salary">
精确查找:<input type="checkbox" ng-model="exactMatch">
<table class="table table-bordered">
<tr class="danger">
<th>name</th>
<th>salary</th>
</tr>
<tr ng-repeat="people in peoples | filter:searchText:exactMatch"> // * 精确查找
<td>{{ people.name }}</td>
<td>{{ people.salary }}</td>
</tr>
</table>
</div>
<script>
angular.module("myApp", [])
.controller("myController", function($scope) {
var peoples = [
{name:"zhangyu",salary:55000},
{name:"wangwu",salary:35600},
{name:"lisi",salary:2100},
{name:"wanger",salary:61000}
];
$scope.peoples = peoples;
});
</script>
// 在同一搜索框过滤 name、city 两属性
<div ng-controller="myController">
Search name&city: <input type="text" ng-model="searchText"> <br>
<table class="table table-bordered">
<tr class="danger">
<th>name</th>
<th>city</th>
<th>salary</th>
</tr>
<tr ng-repeat="people in peoples | filter:search">
<td>{{ people.name }}</td>
<td>{{ people.city }}</td>
<td>{{ people.salary }}</td>
</tr>
</table>
</div>
<script>
angular.module("myApp", [])
.controller("myController", function($scope) {
var peoples = [
{name:"zhangyu",city:"jinan",salary:55000},
{name:"wangwu",city:"beijing",salary:35600},
{name:"lisi",city:"shanghai",salary:2100},
{name:"wanger",city:"shenzhen",salary:61000}
];
$scope.peoples = peoples;
$scope.search = function(item){ // 把表格传进来
if($scope.searchText == undefined ||
item.name.toLowerCase().indexOf($scope.searchText.toLowerCase()) != -1 ||
item.city.toLowerCase().indexOf($scope.searchText.toLowerCase()) != -1){
return true; // 有符合条件的就返回
}
return false;
};
});
</script>
关键:在
angular
的.filter()
方法中返回自定义函数,本例把城市编号转换成对应的城市名
<div ng-controller="myController">
<table class="table table-bordered">
<tr class="danger">
<th>name</th>
<th>city</th>
<th>salary</th>
</tr>
<tr ng-repeat="people in peoples | filter:search">
<td>{{ people.name }}</td>
<td>{{ people.cityNum |city }}</td> // 过滤器的名字
<td>{{ people.salary }}</td>
</tr>
</table>
</div>
<script>
angular.module("myApp", [])
.filter("city",function(){ // 定义过滤器
return function (cityNum) { // 返回自定义过滤器的实现
switch (cityNum){
case 1:
return "beijing";
case 2:
return "shanghai";
case 3:
return "shenzhen";
}
}
})
.controller("myController", function($scope) {
var peoples = [
{name:"zhangyu",cityNum:1,salary:55000},
{name:"wangwu",cityNum:2,salary:35600},
{name:"lisi",cityNum:1,salary:2100},
{name:"wanger",cityNum:3,salary:61000}
];
$scope.peoples = peoples;
});
</script>
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
...
}, function errorCallback(response) {
...
});
实例:
<div ng-controller="myController">
{{data}}
{{error}}
</div>
<script>
angular.module("myApp", [])
.controller("myController", function($scope, $http, $log) {
$http({
method:'GET',
url:'a.php'
}).then(function(response){
$scope.data = response.data;
},function(response){
$scope.error = response.data;
});
});
</script>
// a.php
echo json_encode("ok!");
这种写法并不简单易读,所以我们应该把 成功&失败 的回调函数提取出来
<script>
angular.module("myApp", [])
.controller("myController", function($scope, $http, $log) {
var successCallBack = function(response){
$scope.data = response.data;
$log.log(response);
};
var errCallBack = function(response){
$scope.error = response.data;
$log.log(response);
};
$http({
method:'GET',
url:'a.php'
}).then(successCallBack,errCallBack);
});
</script>
在控制台打印不同类型的日志信息
log();
info();
warn();
error();
debug();
<div ng-controller="myController">
{{data.name}}
</div>
<script>
angular.module("myApp", [])
.controller("myController", function($scope, $http, $log) {
$http({
method:'GET',
url:'a.php'
}).then(function(res){
$scope.data = res.data;
$log.log(res); // *
});
});
</script>
$location 服务提供了一些访问与操作URL的方法。
hash() 在url的尾部添加 "#xxx",详细实例见\$anchorScroll
$anchorScroll() 去当前url指定位置,通常与$location.hash连用,实现锚点
<div ng-controller="myController">
<button id="top" ng-click="scrollTo('bottom')">go to the bottom</button>
<div class="pad">
<p>hello world!</p>
<p>hello world!</p>
...
<p>hello world!</p>
</div>
<button id="bottom" ng-click="scrollTo('top')">go to the top</button>
</div>
<script>
var myapp = angular.module("myApp", [])
.controller("myController", function($scope,$location,$anchorScroll) {
$scope.scrollTo = function (ScrollLocation) {
$location.hash(ScrollLocation);
$anchorScroll();
}
});
</script>
$q服务是AngularJS中自己封装实现的一种Promise实现, promise解决的是异步编程的问题。
假设有一个家具厂,而它有一个VIP客户张先生。
有一天张先生需要一个豪华衣柜,于是,他打电话给家具厂说我需要一个衣柜,回头做好了给我送来, 这个操作就叫$q.defer,也就是延期,因为这个衣柜不是现在要的,所以张先生这是在发起一个可延期的请求。
同时,家具厂给他留下了一个回执号,并对他说:我们做好了会给您送过去,放心吧。这叫做promise,也就是承诺。
这样,这个defer算是正式创建了,于是他把这件事记录在自己的日记上,并且同时记录了回执号,这叫做deferred,也就是已延期事件。
现在,张先生就不用再去想着这件事了,该做什么做什么,这就是“异步”的含义。
假设家具厂在一周后做完了这个衣柜,并如约送到了张先生家(包邮哦,亲),这就叫做deferred.resolve(衣柜),也就是“已解决”。而这时候张先生只要签收一下这个(衣柜)参数就行了,当然,这个“邮包”中也不一定只有衣柜,还可以包含别的东西,比如厂家宣传资料、产品名录等。整个过程中轻松愉快,谁也没等谁,没有浪费任何时间。
假设家具厂在评估后发现这个规格的衣柜我们做不了,那么它就需要deferred.reject(理由),也就是“拒绝”。拒绝没有时间限制,可以发生在给出承诺之后的任何时候,甚至可能发生在快做完的时候。而且拒绝时候的参数也不仅仅限于理由,还可以包含一个道歉信,违约金之类的,总之,你想给他什么就给他什么,如果你觉得不会惹恼客户,那么不给也没关系。
假设家具厂发现,自己正好有一个符合张先生要求的存货,它就可以用$q.when(现有衣柜)来把这个承诺给张先生,这件事就立即被解决了,皆大欢喜,张先生可不在乎你是从头做的还是现有的成品,只会惊叹于你们的效率之高。
假设这个家具厂对客户格外的细心,它还可能通过deferred.notify(进展情况)给张先生发送进展情况的“通知”。
这样,整个异步流程就圆满完成,无论成功或者失败,张先生都没有往里面投入任何额外的时间成本。
好,我们再扩展一下这个故事:
张先生这次需要做一个桌子,三把椅子,一张席梦思,但是他不希望今天收到个桌子,明天收到个椅子,后天又得签收一次席梦思,而是希望家具厂做好了之后一次性送过来,但是他下单的时候又是分别下单的,那么他就可以重新跟家具厂要一个包含上述三个承诺的新承诺,这就是$q.all(桌子承诺,椅子承诺,席梦思承诺),这样,他就不用再关注以前的三个承诺了,直接等待这个新的承诺完成,到时候只要一次性签收了前面的这些承诺就行了。
———— 摘自大神 @雪狼
再来看一下程序版本的讲解:
1、$q是Angular的一种内置服务,它可以使你异步地执行函数,并且当函数执行完成时它允许你使用函数的返回值(或异常)。
2、defer的字面意思是延迟, $q.defer() 可以创建一个deferred实例(延迟对象实例)。deferred 实例旨在暴露派生的Promise实例,以及被用来作为成功完成或未成功完成的信号API,以及当前任务的状态。这听起来好复杂的样子,总结$q, defer, promise三者之间的关系如下所示。
var deferred = $q.defer(); //通过$q服务注册一个延迟对象 deferred
var promise = deferred.promise; //通过deferred延迟对象,可以得到一个承诺promise,而promise会返回当前任务的完成结果
defer的方法:
1. deferred.resolve(value) 成功解决(resolve)了其派生的promise。参数value将来会被用作promise.then(successCallback(value){...}, errorCallback(reason){...}, notifyCallback(notify){...})中successCallback函数的参数。
2. deferred.reject(reason) 未成功解决其派生的promise。参数reason被用来说明未成功的原因。此时deferred实例的promise对象将会捕获一个任务未成功执行的错误,promise.catch(errorCallback(reason){...})。补充一点,promise.catch(errorCallback)实际上就是promise.then(null, errorCallback)的简写。
3. notify(value) 更新promise的执行状态(翻译的不好,原话是provides updates on the status of the promise's execution)
栗子:
function asyncGreet(name) {
var deferred = $q.defer(); //通过$q.defer()创建一个deferred延迟对象,在创建一个deferred实例时,也会创建出来一个派生的promise对象,使用deferred.promise就可以检索到派生的promise。
deferred.notify('About to greet ' + name + '.'); //延迟对象的notify方法。
if (okToGreet(name)) {
deferred.resolve('Hello, ' + name + '!'); //任务被成功执行
} else {
deferred.reject('Greeting ' + name + ' is not allowed.'); //任务未被成功执行
}
return deferred.promise; //返回deferred实例的promise对象
}
function okToGreet(name) { //只是mock数据,实际情况将根据相关业务实现代码
if(name == 'Superman') return true;
else return false;
}
var promise = asyncGreet('Superman'); //获得promise对象
//promise对象的then函数会获得当前任务也就是当前deferred延迟实例的执行状态。它的三个回调函数分别会在resolve(), reject() 和notify()时被执行
promise.then(function(greeting) {
alert('Success: ' + greeting);
}, function(reason) {
alert('Failed: ' + reason);
}, function(update) {
alert('Got notification: ' + update);
});
var Todo = $resource('/api/1/todo/:id');
//create a todo
var todo1 = new Todo();
todo1.foo = 'bar';
todo1.something = 123;
todo1.$save();
//get and update a todo
var todo2 = Todo.get({id: 123});
todo2.foo += '!';
todo2.$save();
//which is basically the same as...
Todo.get({id: 123}, function(todo) {
todo.foo += '!';
todo.$save();
});
//get a list of todos
Todo.query(function(todos) {
//do something with todos
angular.forEach(todos, function(todo) {
todo.foo += ' something';
todo.$save();
});
});
//delete a todo
Todo.$delete({id: 123});
// index.html
<div ng-controller="myController">
<table class="table">
<tr>
<th>Input String</th>
<td><input type="text" ng-model="input"></td>
</tr>
<tr>
<th>Result</th>
<td><input type="text" ng-model="output"></td>
</tr>
</table>
<button class="btn btn-primary" ng-click="go(input)">go!</button>
</div>
<script src="angular-1.5.8/angular.min.js"></script>
<script src="js/indexController.js"></script>
<script src="js/stringService.js"></script>
// indexController.js
var myapp = angular.module("myApp", [])
.controller("myController", function($scope,stringService) { // 注入服务
$scope.go = function(input){
$scope.output = stringService.processString(input); // 调用服务的方法
};
});
// stringService.js
myapp.factory('stringService',function(){
return { // 需要返回一个对象
processString: function (input) { // 服务的方法(方法名:函数)
if(!input){
return input;
}
var output = "";
for(var i = 0; i<input.length;i++){
if(i > 0 && input[i] == input[i].toUpperCase()){
output = output + " ";
}
output = output + input[i];
}
return output;
}
}
});