修真院Web工程师零基础全能课

本节课内容

AngularJs进阶-作用域和控制器

主讲人介绍

沁修,葡萄藤技术总监

项目经验丰富,擅长H5移动项目开发。

专注技术选型、底层开发、最佳代码实践规范总结与推广。

直播录屏版

传送门:https://v.qq.com/x/page/t0782...

文字解析版

什么是scope作用域?

scope作用域是一个指向应用model的对象object,也是表达式的执行环境。

作用域有层次结构,有根作用域,有很多子作用域,根据位置不同而不同。

作用域还能监控表达式,传递事件。

比如在html当中,我们都会定义一个ng-app指令,那么随之而来就是一个作用域产生了。

不过由ng-app生成的作用域比较特殊,它是一个根作用域$rootscope,也就是其他所有scope的顶层。

除此之外,还有很多指令都会产生一个作用域,比如ng-controller, ng-repeat等。这些作用域都拥有自己的继承上下文,并且根作用域都是rootscope。

在我们生成一个作用域之后,$scope对象就代表了这个作用域的数据。

我们可以在$scope内定义各种数据,之后可以直接在html中以双花括号的表达式的方式来让html得到这个变量。

scope的用法?

在正式开始接触scope之前我们再来熟悉一下js的全局变量和局部变量:

var foo = "foo";

function bar() {

var foo = "bar";

console.log(foo);

}

bar();

console.log(foo);

这里说明,全局变量可以在方法内引入,而局部变量只能在定义的方法内使用,angular作用域跟变量性质相似。

angularjs中的全局作用域:

var myApp = angular.module('myApp', []);

/*

  • run方法用于初始化全局的数据,仅对全局作用域起作用。
  • 这里的run方法只会在angular启动的时候运行一次。

*/

myApp.run(function($rootScope){

$rootScope.version = 2.0;

});

全局作用域是所有controller的scope的桥梁。

rootscope定义的值,可以在各个controller中使用。

经常用于需要在多个页面场景中的数据就可以定义到全局作用域上。

angularjs中的局部作用域:

myApp.controller('homeCtrl', function($scope){

$scope.person = {

name: 'max'

}

})

myApp.controller('productCtrl',function($scope,$rootScope){

console.log($scope.person.name);//undefined

console.log($rootScope.version) //2.0

})

前面我们已经说过,每一个angular应用有且只有一个root scope,但可以拥有多个child scope。

因为一些directive会创建新的child scope,当新的scope被创建后,他们将作为一个child scope,加入到parent scope中。

这样,创建了一个与它们附属的DOM相似的树结构。

当angular在html中对{{person}}求值时,它首先查看与当前元素关联的scope的person属性。

如果没有找到对应的属性,它将会一直向上搜索parent scope,直到到达root scope。

在javascript中,这个行为被称为“原型继承”,child scope典型地继承自它们的parent。

$scope特点?

提供了$watch()方法,用于监听模型的变化

提供了$apply()方法,用于传播模型的变化

$watch()监听模型变化,当模型发生变化,它会给你提示。

表达式:

$watch(watchExpression, listener, objectEquality); 

watchExpression:监听的对象,比如一个angular表达式如’scope.person’。

listener:当watchExpression变化时会被调用的函数或者表达式,它接收3个参数:

newValue(新值), oldValue(旧值), scope(作用域的引用)。

objectEquality:是否深度监听,如果设置为true,它告诉Angular检查所监控的对象中每一个属性的变化.。

如果你希望监控数组的个别元素或者对象的属性而不是一个普通的值, 那么你应该使用它。

$scope.name = 'hello';

$scope.$watch('name',function(newValue, oldValue, scope){

console.log(newValue);

console.log(oldValue);

});

$timeout(function(){

$scope.name = "world";

},1000);

$apply()用于传播模型的变化。

AngularJS 外部的控制器(DOM 事件、外部的回调函数如jQuery等)调用了AngularJS 函数之后,就需要调用$apply。

myApp.controller('homeCtrl', function($scope){

vm.name = 'hello';

setTimeout(function () {

vm.name = "world";

}, 2000);

})

预期的应该是先显示hello, 两秒后改为world。

但事实是我们发现它不会自动变化,因为调研了外部的事件,所以需要用$apply方法就可以了:

myApp.controller('homeCtrl', function($scope){

vm.name = 'hello';

setTimeout(function () {

$scope.$apply(function () {

vm.name = "world";

});

}, 2000);

})

$scope的生命周期?

创建 creation

注册监视器 watcher registration

模型变化 model mutation

变化检测 mutation observation

作用域销毁 scope destruction

浏览器正常的事件流中,当浏览器接收到事件后,它会执行一个相应的javascript回调。

一旦回调函数执行完毕后,浏览器将会重绘DOM,并返回到继续等待事件的状态。

1.在应用启动的过程中,会创建rootscope,而后在模板的链接过程中,一些directive会创建新的child scope。

2.directive在scope中注册$watch,这些watch会用来向DOM传播model的值。

3.更新模型状态必须是在$apply方法中才可以被观察到,不过angular框架是封装了这个方法过程的。

我们通常无需担心,除非是之前提到过的,angular以外的一些方法事件在触发后,不能正常调用$apply才需要手动去添加这个方法。

4.$apply方法结束后,angular会在根作用域执行一个$digest周期并且扩散到所有子作用域。

scope检查所有$watch监听的表达式,将现在的值与旧的值作比较。

这个过程会检查模型状态是否改变以及更新。

5.销毁作用域,当不在需要子作用域的时候,就会被销毁掉。

总结$scope?

1、提供了观察者可以监听数据模型的变化

2、可以将数据模型的变化通知给整个 App

3、可以进行嵌套,隔离业务功能和数据

4、给表达式提供上下文执行环境

在scope之后我们又来看看和它关系非常紧密的控制器controller。。。

什么是控制器?

从作用上来讲,controller主要是对视图中的数据和事件函数进行挂载,同时处理一些业务的地方。

从功能上来讲,在angularjs中,controller是一个js函数,用来扩展angular的子scope的实例。

因此它可以用来设置scope对象的初始状态,并且增加一些属性行为到scope中。

控制器使用?

在模板中声明控制器

<div ng-controller="myController">...</div>

控制器实际上就是一个js的构造函数:

//控制器类定义

var myControllerClass = function($scope){

//模型属性定义

$scope.text = "...";

//模型方法定义

$scope.do = function(){...};

};

//在模块中注册控制器

angular.module('someModule',[])

.controller("myController",myControllerClass);

控制器构造函数仅在AngularJS对HTML文档进行编译时被执行一次。

一旦控制器创建完毕,就意味着scope对象上的业务模型构造完毕,此后就不再需要控制器了,因为scope对象接管了。

控制器和scope?

<html ng-app=“myApp">

<body ng-init=“foo={name:’hello'}”>

<div ng-controller=“myCtrl"></div>

</body>

</html>

对scope的影响是什么样的呢?

$rootScope: {

foo: {name: ‘hello'}

}

scope: {

prototype: $rootScope,

bar: ...

}

可以看到ng-app指令创建了$rootScope对象,这个时候它还是一个空对象。

body元素对应的scope对象还是$rootScope,ng-init指令将foo对象挂到了$rootScope上

div元素又通过ng-controller指令创建了一个新的scope对象,这个对象的原型是$rootScope

因为继承关系,如果在scope中引用foo会指向$rootScope.foo

注意不要在controller中做的事情:

1.DOM操作

2.表单输入的格式化,用form controls

3.输出内容的格式化和过滤,用filter

4.控制器之间的数据共享,另外定义services服务来处理

以上就是上节课的内容解析啦


用户bPbdDlb
422 声望36 粉丝