AngularJS学习——作用域与事件
JavaScript对象是基于key-value键值对的,我们可以把JavaScript对象作为一个map数据结构使用,而AngularJS作用域本质上就是一个普通的JavaScript对象。
AngularJS作用域对象和普通JavaScript对象一样,都可以在作用域对象中增加属性或者方法,不同的是我们不需要手动去构造作用域对象,当HTML页面中出现ng-app和ng-controller指令时,AngularJS框架会自动创建作用域对象,我们只需要将其注入即可。
AngularJS程序中作用域的主要功能是存放模型数据,在控制器中,我们可以修改作用域中的模型数据或在作用域中新增模型数据。
eg:
$scope.name = "chenxiaoming" //在模型中新增模型数据
<!--在视图中展示模型数据-->
<p>{{name}}</p>
每个AngularJS应用至少会有一个名称为$rootScope作用域,它是AngularJS应用的根作用域。
当页面中出现ng-app指令,启动AngularJS框架,并且自动创建一个根作用域对象$rootScope,接着使用ng-controller指令实例化控制器对象时,AngularJS框架会为我们创建一个子作用域$scope,默认该子作用域会继承$rootScope作用域的所有属性。($rootScope是所有作用域的父作用域,孤立作用域除外。)
eg:
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8">
<title>继承$rootScope</title>
<script src="../lib/angular-1.6.5/angular.min.js"></script>
</head>
<body ng-init="name='chenxiaoming';age=18">
<div ng-controller="myCtrl"></div>
<script>
angular.module("myApp",[])
.controller("myCtrl", ["$scope", "$log", function($scope, $log){
$log.info($scope.name);
$log.info($scope.age);
}])
</script>
</body>
</html>
案例中通过ng-init指令在$rootScope作用域对象中新增了两个属性,即name和age。
接着使用ng-controller指令实例化myCtrl控制器,此时AngularJS会创建一个子作用域对象继承自$rootScope,可以在$scope中调用$rootScope中的属性。
作用域嵌套
eg:
<body ng-app="myApp">
<div ng-controller="myFirstCtrl">
<div ng-controller="mySecondCtrl"></div>
</div>
</body>
作用域嵌套就类似案列中的结构一样,图解如下
AngularJS作用域对象原型继承
AngularJS作用域对象继承采用构造方法原型链继承。(这个我还没有具体搞懂,搞懂之后慢慢在别的博客中详细说明)
AngularJS作用域高级特性
主要讲述几个方法,包括作用域属性监视、digest循环等。
1.$watch方法监视作用域
AngularJS为我们提供了一个非常方便的$watch()方法,可以帮助我们监视作用域中的属性的变。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板</title>
<script src="../lib/angular.min.js"></script>
</head>
<body ng-app="myApp">
<input type="text" ng-model="name">
<div>change count: {{ count }}</div>
<script>
angular.module("myApp",[])
.run(["$rootScope",function($rootScope){
$rootScope.count = 0;
$rootScope.name = "chenxiaoming";
$rootScope.$watch("name",function(){
$rootScope.count ++;
})
}])
</script>
</body>
</html>
$watch()方法对$rootScope中的name属性进行监视,并在它发生变化的时候将$rootScope中的count属性值增加1。
注意:以上$watch监视的内容是一个基本类型。AngularJS作用域对象的$watch方法中,对基本类型和应用类型的操作有所不同。
下面是引用类型的例子
eg:
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8">
<title>$watch引用类型</title>
<script src="../lib/angular-1.6.5/angular.min.js"></script>
</head>
<body>
<div ng-repeat="item in items">
<input type="text" ng-model="item.value"> <span>{{item.value}}</span><br><br>
</div>
<div>change count: {{count}}</div>
<script>
var app = angular.module("myApp",[]);
app.run(["$rootScope",function($rootScope){
$rootScope.count = 0;
$rootScope.items = [
{"value" : 1},
{"value" : 2},
{"value" : 3},
{"value" : 4},
{"value" : 5},
];
$rootScope.$watch("items",function(){
$rootScope.count ++;
},false)
//$watch中添加第三个参数true/false,默认的false引用监视,true是全等监视
}])
</script>
</body>
</html>
例子中,对input框中的内容进行修改,就会发现count的值始终不变。
$watch()方法的三个参数。第一个参数是要监视的属性,第二个参数是在监视属性发生变化时需要回调的方法。第三个参数就是对监视对象的类型进行设置。默认的是false,即引用监视(reference watch),监视的对象引用没有发生变化就不算变化。可修改值为true,即全等监视(equality watch),此时只要监视的属性发生变化,$watch就会执行相应的回调方法。
全等监视固然好,但是在运行时需要先遍历整个监视对象,然后在每次$digest之前使用angular.copy()将整个对象深复制一遍,然后在运行之后用angular.equal()将前后的对象进行对比。全等监视这一个设置消耗大量的资源,会让应用停止不前。实际使用当中,需要权衡。
angular1.1.4版本之后,新增一个$watchCollection()方法针对数组进行监视。性能介于全等监视和引用监视之间,即它并不会对数组中每一项的属性进行监视,但是可以对数组的项目增减做出反应。
2.作用域监视解除
$watch方法的发回值,该方法调用完毕后返回另一个方法,调用返回的方法即可解除作用域监视。
unbindWatcher()解除作用域监视。
eg:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>作用域监视解除</title>
<script src="../lib/angular.min.js"></script>
</head>
<body ng-app="myApp">
<input type="number" ng-model="num">
<div>change count : {{ count }}</div>
<script>
angular.module("myApp",[])
.run(["$rootScope",function($rootScope){
$rootScope.num = 0;
$rootScope.count = 100;
var unbindWatcher = $rootScope
.$watch("num",function(newValue,oldValue){
if(newValue == 2){
unbindWatcher();
}else{
$rootScope.count++;
}
});
}])
</script>
<!-- 当文本值为2时,我们调用$watch()返回的方法unbindWatcher()解除了作用域监视,所以再次修改文本框内容是count值不再累加 -->
</body>
</html>
3.$apply方法与$digest循环
这两个是AngularJS中的核心概念。深入AngularJS双向数据绑定实现原理,就要理解这两个的概念。
eg:
<input type="text" ng-model="name">
<div>{{name}}</div>
上面所示,是一个简单的数据绑定,当input框中的数据改变,div中的AngularJS的表达式的{{name}}也会跟着改变。AngualrJS在实现双向数据绑定时,会在后台自动帮$scope中设置一个watcher,用来在数据发生变化的时候更新View。
即:
$scope.$watch("name",function(newValue, oldValue){
//数据发生改变会跟新View
});
AngularJS通过
$digest循环来触发watcher,从而知道name属性是否发生改变,调用相应的回调方法。$digest会周期性的运行来检查scope模型中的数据是否发生变化。
$digest循环中,watchers会被触发。当一个watcher被触发时,AngularJS会检测scope模型,如果他发生了变化,那么关联到该watcher的回调方法就会被调用。
以上笔记整理自个人学习,用做个人学习分享