1. 程式人生 > >理財文章:http://www.jianshu.com/users/026492251c04

理財文章: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