您的位置:首页 > 运维架构

angular数据绑定与监控(学习笔记)

2016-02-04 18:13 701 查看

数据的双向绑定

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: