理財文章:http://www.jianshu.com/users/026492251c04
資料的雙向繫結
angular實現了雙向繫結機制,所謂雙向繫結,就是從介面的操作能實時反映到資料,資料的變更能實時展現到介面.基於單一模型的介面同步
ng-model 指令: 可以將輸入域的值與 AngularJS 建立的變數繫結。<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <body> <div ng-app="myApp" > <span style="white-space:pre"> </span>名字: <input ng-model="name"> <br/>{{name}}</div> <script> var app = angular.module('myApp', []); </script> </body> </html>
在angular中,變數和表示式都依附在一種叫做作用域(scope)的東西上.每個angular應用預設會有一個根作用域($rootScope),如果在介面中繫結未定義的變數,當它被賦值的時候,就會自動建立到對應的作用域上.
"{{}}"這種符號,稱為插值表示式,這裡面的內容將會被動態解析.除了"{{}}"angular還提供了ng-bind來實現一樣的功能.
對模型的二次解析
有的時候,我們需要在介面上顯示性別,男/女,但是在資料庫裡面存的是0或者1,那麼我們就要對它進行一些轉換.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <body> <div ng-app="myApp" ng-controller="myCtrl"> <div>{{formatGender(tom.gender)}}</div> </div> <script> var app = angular.module('myApp', []); app.controller('myCtrl', function($scope) { $scope.tom = { name: "Tom", gender: 1, genderText: "男" }; $scope.formatGender = function(gender) { if (gender == 0){ return "女"; } if (gender == 1){ return "男"; } }; }); </script> </body> </html>
我們這裡利用表示式使用函式的方法對資料進行格式化,其實只是作用於檢視層,不會影響到真實資料模型.
注意:
1:在繫結表示式裡面,只能使用自定義函式,不能使用原生函式.
<div>{{Math.abs(-1)}}</div>
以上是錯誤的例子,如果確實需要呼叫原生函式,可以用一個自定義函式作包裝,在自定義函式裡面可以隨意使用各種原生物件.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <body> <div ng-app="myApp" ng-controller="myCtrl"> <div>{{abs(-1)}}</div> </div> <script> var app = angular.module('myApp', []); app.controller('myCtrl', function($scope) { $scope.abs = function(number) { return Math.abs(number); }; }); </script> </body> </html>
2:上面這個格式化資料的例子只是為了說明可以這麼用,但不表示這是最佳方案.angular為這類需求提供了filter方案,可以在"{{}}"表示式中使用管道操作符來格式化資料.
{{expression | filterName : parameter1 : ...parameterN}}
陣列與物件結構的繫結
有的時候,我們需要把一個數組的資料展示出來,這可以使用ng-repeat指令來處理,它相當於一個迴圈.
單一陣列資料
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<button ng-click="add()">Add Item</button>
<ul>
<li ng-repeat="item in arr1">{{item}}</li>
</ul>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.arr1 = [1, 2, 3];
$scope.add = function() {
$scope.arr1.push($scope.arr1.length + 1);
};
});
</script>
</body>
</html>
這樣就可以把陣列的內容展示到介面上.陣列中的資料變化時,也能實時更新到介面上來.
但有時候,我們會遇到數組裡有重複元素的情況,這時候,ng-repeat程式碼就不能起作用,原因是angular預設需要在陣列中使用唯一索引,如果這遇到這情況,那就可以指定它使用序號作為索引即可.
含有重複值的陣列資料
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<button ng-click="add()">Add Item</button>
<ul>
<li ng-repeat="item in arr1 track by $index">{{item}}</li>
</ul>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.arr1 = [1,1,1,1, 2, 3];
$scope.add = function() {
$scope.arr1.push($scope.arr1.length + 1);
};
});
</script>
</body>
</html>
多維陣列
可以用多層迴圈方式迭代出來:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<ul>
<li ng-repeat="childArr in arr3 track by $index">
{{$index}}
<ul>
<li ng-repeat="item in childArr track by $index">{{item}}</li>
</ul>
</li>
</ul>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.arr3 = [
[11, 12, 13],
[21, 22, 23],
[31, 32, 33]
];
});
</script>
</body>
</html>
陣列元素是物件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<table class="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="child in arr4">
<td>{{child.name}}</td>
<td>{{child.age}}</td>
</tr>
</tbody>
</table>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.arr4 = [{
name: "Tom",
age: 5
}, {
name: "Jerry",
age: 2
}];
});
</script>
</body>
</html>
遍歷物件屬性
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<ul>
<li ng-repeat="(key, value) in obj">{{key}}: {{value}}</li>
</ul>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.obj = {
a: 1,
b: 2,
c: 3
};
});
</script>
</body>
</html>
如果單純想要值,也可以不用這麼麻煩,直接用陣列的寫法即可,就算有物件值重複,也不用像陣列那樣需要指定$index做索引,因為它是物件的key來做索引的,這是不會重複的.你見過兩個同名的屬性?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<ul>
<li ng-repeat="key in obj"> {{key}}</li>
</ul>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.obj = {
a: 1,
b: 2,
c: 3
};
});
</script>
</body>
</html>
資料監控
有時候,我們不是直接把資料繫結到介面上,而是先要賦值到其他變數上,或者針對資料的變更,做出一些邏輯的處理,這時候就要用到監控.簡單監控的例子
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<button ng-click="changeA()">click me</button>
//{{a}}
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.a = 1;
$scope.$watch("a", function(newValue, oldValue) {
alert(oldValue + " -> " + newValue);
});
$scope.changeA = function() {
$scope.a++;
};
});
</script>
</body>
</html>
對作用域上的變數新增監控後,就可以在變數變更時候得到通知了.如果說新賦值的變數和原先的相同,這個監控就不會被執行.
以上這種方式可以監控到最直接的賦值,包括各種基本型別,以及複雜型別的引用賦值,比如說下面這個陣列被重新賦值了,就可以被監控到:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<button ng-click="changeArr()">click me</button>
{{a}}
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.arr = [0];
$scope.$watch("arr", function(newValue) {
alert("change:" + newValue.join(","));
});
$scope.changeArr = function() {
$scope.arr = [7, 8];
};
});
</script>
</body>
</html>
但這種監控方式只能處理引用相等的判斷,對於一些更復雜的監控,需要更細緻的處理。比如說,我們有可能需要監控一個數組,但並非監控它的整體賦值,而是監控其元素的變更:
$scope.$watch("arr", function(newValue) {
alert("deep:" + newValue.join(","));
}, true);
$scope.addItem = function() {
$scope.arr.push($scope.arr.length);
};
注意,這裡我們在$watch函式中,添加了第三個引數,這個引數用於指示對資料的深層監控,包括陣列的子元素和物件的屬性等等。
樣式的資料繫結
以上我們提到的例子,都是跟資料同步,資料展示相關,但資料繫結的功能遠不止於此.
我們再來一個例子:
有個資料表,點中其中某條,這條就改變樣式.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
<style>
ul{list-style:none}
.active{
color:red
}
</style>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<ul class="list-group">
<li ng-repeat="item in items" ng-class="{true:' active', false: ' '}[item==selectedItem]" ng-click="select(item)">
{{item.title}}
</li>
</ul>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.items = [];
for (var i=0; i<10; i++) {
$scope.items.push({
title:i
});
}
$scope.selectedItem = $scope.items[0];//預設為第一項
$scope.select = function(item) {
$scope.selectedItem = item;//一點選就把傳入的item賦值給selectedItem
};
});
</script>
</body>
</html>
本例中我們使用一個迴圈來迭代陣列中的元素,並且使用一個變數selectedItem用於標識選中項.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<input type="number" ng-model="x" ng-init="x=12"/>
<div ng-style="{'font-size': x+'pt'}">
測試字型大小
</div>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
});
</script>
</body>
</html>
除了使用ng-class,還可以用ng-style來對樣式進行控制.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
<style>
ul{list-style:none}
.active{
color:red
}
</style>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<input type="number" ng-model="x" ng-init="x=12"/>
<div ng-style="{'font-size': x+'pt'}">
測試字型大小
</div>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
});
</script>
</body>
</html>
狀態控制
有時候,我們除了控制普通的樣式,還可以控制某個介面元素的顯示隱藏,我們用ng-class或者ng-style,當然也可以控制元素的顯示隱藏,但angular給我們提供了一種快捷方式,那就是ng-show/ng-hide.
利用資料繫結,我們可以很容易實現原有的一些顯示隱藏功能.
<button ng-show="selectedItem">有選中項的時候可以點我</button>
<button ng-hide="selectedItem">沒有選中項的時候可以點我</button>
流程控制
除了使用ng-show/ng-hide來控制元素的顯示隱藏,還可以使用ng-if.
所謂的show和hide,意味著DOM元素已經存在,只是控制了是否顯示,而if則起到了流程控制的作用,只有符合條件的DOM元素才會被建立,否則不建立。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<ul>
<li ng-if="condition==1">if 1</li>
<li ng-if="condition==2">if 2</li>
<li ng-show="condition==1">show 1</li>
<li ng-show="condition==2">show 2</li>
</ul>
<button ng-click="change()">change</button>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.condition = 1;
$scope.change = function() {
$scope.condition = 2;
};
});
</script>
</body>
</html>
這個例子初始時候,就建立了3個li,其中一個被隱藏(show2),點選按鈕,仍然是3個li,其中,if1被銷燬了,if2被創建出來了,show1被隱藏了,show2顯示出來了.
所以,我們看到ng-if的節點是動態創建出來的,與此類似,還有ng-switch指令:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-switch="condition">
<div ng-switch-when="A">A</div>
<div ng-switch-when="B">B</div>
<div ng-switch-default>default</div>
</div>
<button ng-click="a()">A</button>
<button ng-click="b()">B</button>
<button ng-click="c()">C</button>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.condition = "";
$scope.a = function() {
$scope.condition = "A";
};
$scope.b = function() {
$scope.condition = "B";
};
$scope.c = function() {
$scope.condition = "C";
};
});
</script>
</body>
</html>
資料聯動
最典型的例子就是省市縣三級聯動.
我們來看這樣一個例子:
有兩個表,第一個的資料變動,對第二個的資料產生過濾.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
<span style="white-space:pre"> </span><style>
<span style="white-space:pre"> </span>.active{color:red}
<span style="white-space:pre"> </span></style></head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<ul class="list-group">
<li ng-repeat="province in provinceArr" ng-class="{true:'list-group-item active', false: 'list-group-item'}[province==selectedProvince]" ng-click="selectProvince(province)">
{{province}}
</li>
</ul>
<ul class="list-group">
<li ng-repeat="city in cityArr" ng-class="{true:'list-group-item active', false: 'list-group-item'}[city==selectedCity]" ng-click="selectCity(city)">
{{city}}
</li>
</ul>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.provinceArr = ["江蘇", "雲南"];
$scope.cityArr = [];
$scope.$watch("selectedProvince", function(province) {//監聽<span style="font-family: Arial, Helvetica, sans-serif;">selectedProvince值的</span>變化
// 真正有用的程式碼在這裡,實際場景中這裡可以是呼叫後端服務查詢的關聯資料
switch (province) {
case "江蘇": {
$scope.cityArr = ["南京", "蘇州"];
break;
}
case "雲南": {
$scope.cityArr = ["昆明", "麗江"];
break;
}
}
});
$scope.selectProvince = function(province) {
$scope.selectedProvince = province; //選中給樣式
};
$scope.selectCity = function(city) {
$scope.selectedCity = city;//選中給樣式
};
});
</script>
</body>
</html><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
<span style="white-space:pre"> </span><style>
<span style="white-space:pre"> </span>.active{color:red}
<span style="white-space:pre"> </span></style>
<span style="white-space:pre"> </span></head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<ul class="list-group">
<li ng-repeat="province in provinceArr" ng-class="{true:'list-group-item active', false: 'list-group-item'}[province==selectedProvince]" ng-click="selectProvince(province)">
{{province}}
</li>
</ul>
<ul class="list-group">
<li ng-repeat="city in cityArr" ng-class="{true:'list-group-item active', false: 'list-group-item'}[city==selectedCity]" ng-click="selectCity(city)">
{{city}}
</li>
</ul>
<span style="white-space:pre"> </span>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.provinceArr = ["江蘇", "雲南"];
$scope.cityArr = [];
$scope.$watch("selectedProvince", function(province) {//監聽selectedProvince值的變化
// 真正有用的程式碼在這裡,實際場景中這裡可以是呼叫後端服務查詢的關聯資料
switch (province) {
case "江蘇": {
$scope.cityArr = ["南京", "蘇州"];
break;
}
case "雲南": {
$scope.cityArr = ["昆明", "麗江"];
break;
}
}
});
$scope.selectProvince = function(province) {
$scope.selectedProvince = province; //選中給樣式
};
$scope.selectCity = function(city) {
$scope.selectedCity = city;//選中給樣式
};
<span style="white-space:pre"> </span>
});
</script>
</body>
</html>
如果繫結到下拉框上,程式碼更簡單
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<select class="form-control col-md-6" ng-model="selectedProvince" ng-options="province for province in provinceArr"></select>
<select class="form-control col-md-6" ng-model="selectedCity" ng-options="city for city in cityArr"></select>
<span style="white-space:pre"> </span>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.provinceArr = ["江蘇", "雲南"];
$scope.cityArr = [];
$scope.$watch("selectedProvince", function(province) {//監聽selectedProvince值的變化
// 真正有用的程式碼在這裡,實際場景中這裡可以是呼叫後端服務查詢的關聯資料
switch (province) {
case "江蘇": {
$scope.cityArr = ["南京", "蘇州"];
break;
}
case "雲南": {
$scope.cityArr = ["昆明", "麗江"];
break;
}
}
});
<span style="white-space:pre"> </span>
});
</script>
</body>
</html>
從這個例子,我們看到,相比傳統前端開發方式那種手動監聽事件,手動更新DOM的方式,使用angular資料繫結做資料聯動真的太容易了.如果把這個例子改造成三級聯動,只需要對selectedCity也做一個監控就可以了.
小結
剛剛我們已經看到資料繫結的各種使用場景了,資料繫結一切的核心就是資料.資料變更導致頁面的更新,如果我們想要更新介面,只需修改資料即可.
來自
https://github.com/xufei/blog/issues/14