1、數據->模板
數據到表現的綁定,主要是使用模板標記直接完成的:
<p>{{ w }} x{{ h }}</p>
使用 {{ }}這個標記,就可以直接引用,並綁定一個作用域內的變量。在實現上, ng 自動創建瞭一個 watcher。效果就是,不管因為什麼,如果作用域的變量發生瞭改變,我們隨時可以讓相應的頁面表現也隨之改變。我們可以看一個更純粹的例子:
<p id="test" ng-controller="TestCtrl">{{ a }}</p>
<script type="text/javascript">
angular.module('app', [],angular.noop)
.controller('TestCtrl', function($scope){
$scope.a = '123';
});
angular.bootstrap(document.documentElement,['app']);
</script>
上面的例子在頁面載入之後,我們可以在頁面上看到 123。這時,我們可以打開一個終端控制器,輸入:
$('#test').scope().a= '12345';
$('#test').scope().$digest();
上面的代碼執行之後,就可以看到頁面變化瞭。
對於使用 ng進行的事件綁定,在處理函數中就不需要去關心 $digest() 的調用瞭。因為 ng 會自己處理。源碼中,對於 ng 的事件綁定,真正的處理函數不是指定名字的函數,而是經過 $apply() 包裝過的一個函數。這個 $apply()做的一件事,就是調用根作用域 $rootScope 的 $digest() ,這樣整個世界就清凈瞭:
<p id="test" ng-controller="TestCtrl"ng-click="click()">{{ a }}</p>
<script type="text/javascript">
angular.module('app', [],angular.noop)
.controller('TestCtrl', function($scope){
$scope.a = '123';
$scope.click = function(){
$scope.a = '456';
}
});
angular.bootstrap(document.documentElement,['app']);
</script>
那個 click 函數的定義,綁定時變成瞭類似於:
function(){
$scope.$apply(
function(){
$scope.click();
}
)
}
這裡的 $scope.$apply()中做的一件事:
$rootScope.$digest();
2. 模板->數據
模板到數據的綁定,主要是通過 ng-model 來完成的:
<input type="text" id="test" ng-controller="TestCtrl"ng-model="a"/>
<script type="text/javascript">
angular.module('app', [],angular.noop)
.controller('TestCtrl', function($scope){
$scope.a = '123';
});
angular.bootstrap(document.documentElement,['app']);
</script>
這時修改 input 中的值,然後再在控制終端中使用:
$('#test').scope().a
查看,發現變量 a 的值已經更改瞭。
實際上, ng-model是把兩個方向的綁定都做瞭。它不光顯示出變量的值,也把顯示上的數值變化反映給瞭變量。這個在實現上就簡單多瞭,隻是綁定 change事件,然後做一些賦值操作即可。不過 ng 裡,還要區分對待不同的控件。
3. 數據->模板->數據->模板
現在要考慮的是一種在現實中很普遍的一個需求。比如就是我們可以輸入數值,來控制一個矩形的長度。在這裡,數據與表現的關系是:
長度數值保存在變量中
變量顯示於某個 input 中
變量的值即是矩形的長度
input 中的值變化時,變量也要變化
input 中的值變化時,矩形的長度也要變化
當然,要實現目的在這裡可能就不止一種方案瞭。按照以前的做法,很自然地會想法,綁定input 的 change事件,然後去做一些事就好瞭。但是,我們前面提到過 ng-model 這個東西,利用它就可以在不手工處理 change 的條件下完成數據的展現需求,在此基礎之上,我們還需要做的一點,就是把變化後的數據應用到矩形的長度之上。
最開始,我們面對的應該是這樣一個東西:
<p ng-controller="TestCtrl">
<p style="width: 100px; height: 10px; background-color:red"></p>
<input type="text" name="width" ng-model="width" />
</p>
<script type="text/javascript">
angular.module('app', [],angular.noop)
.controller('TestCtrl', function($scope){
$scope.width = 100;
});
angular.bootstrap(document.documentElement,['app']);
</script>
我們從響應數據變化,但又不使用 change事件的角度來看,可以這樣處理寬度變化:
angular.module('app',[], angular.noop)
.controller('TestCtrl',function($scope){
$scope.width = 100;
$scope.$watch('width',
function(to, from){
$element.children(':first').width(to);
}
);
});
使用 $watch() 來綁定數據變化。
當然,這種樣式的問題,有更直接有效的手段, ng 的數據綁定總是讓人驚異:
<p ng-controller="TestCtrl">
<p style="width: 10px; height: 10px; background-color:red" ng-style="style">
</p>
<input type="text" name="width" ng-model="style.width" />
</p>
<script type="text/javascript">
angular.module('app', [],angular.noop)
.controller('TestCtrl', function($scope){
$scope.style = {width: 100 + 'px'};
});
angular.bootstrap(document.documentElement,['app']);
</script>