scope基于原型的继承性
视图存在嵌套的时候,内层的controller是可以继承到外层的controller数据的。
scope在angularjs里的继承性(基于原型的继承性):
html:Parent { {info}}child { {info}}
当页面一开始加载完毕之后,通过在parent
的input
里面输入内容的时候,在child
的input
里面也会发生响应。这个时候,subController
里的info
的值,是继承parent
里面的mainController
的值。
此时,如果在child
的input
里面输入内容,会发现child
里面的info
发生了变化,但是parent
里面并未发生变化。
此时如果在parent
的Input
里面输入值的话,仅仅是Parent
的info
发生了变化,而child
的info
是不会发生变化的。
然后我再换一种写法
html:parent { {msg.info}}js: app.controller('mainController', function(){ $scope.msg = { info: 'message' }; }); app.controller('subController', function(){ });child { {msg.info}}
ng-model
此时变成了某个对象的属性。那么现在不管你更改的是parent
中的input
还是child
中的input
,都会引起视图相应的变化。
这2者的区别就是在subController
中继承了mainController
中的作用域。当ng-model
是primitive
值时,刚初始化的时候,在subController
里面因为,会新建一个相同的变量,这个时候,如果再在subController
里面获取这个primitive
的时候,就直接在subController
里面就能得到。
而如果mainController
里面的ng-model
是个对象的属性的时候,subController
里面ng-model
是对这个对象的引用。那么不管更改mainController
还是subController
里面的ng-model
视图里面都会发生变化。
在Angularjs里面$scope
有个$watch
方法,当需要时更新DOM。通过监听某个model的是否发生变化来触发相应的callback
。
依然是上面的例子:
html:parentjs: app.controller('mainController', function(){ $scope.msg = { info: 'message' }; $scope.$watch('msg', function(val){ console.log(val); }) });
除了页面初始化后,控制台会输出{info: 'message'}
外,不过input里面的值如何变化。控制台都不会输出任何内容了。这是因为$watch
是比较的msg这个对象的引用是否发生了变化,很显然这个地方msg的引用(heap里面存放的地址)并没用发生变化,仅仅是msg.info的值发生了变化。
$scope.$watch('msg', function(val){ console.log(val); }, true);
这个是否就能监听到msg.info
发生变化后,msg
的内容了。第三个属性boolean
值,当为true,规定的是比较对象的值,而不是引用。
ng-repeat
会给每个循环新建一个作用域。
ng-include
和ng-view
都是动态加载视图,这个时候也会新建作用域
当然还有ng-switch
,directive
也会有这种scope
继承的情况出现。
具体深入理解angularjs
的scope
,请移步
Angularjs 1.2 “Controller as” polyfill
html:{ {parent.name}}js: app.controller('parentController', ApiParentFn); function ApiCtrlFn(){ this.name = 'XL'; } app.controller('childController', ApiChildFn); function ApiChildFn(){ this.name = 'xl'; }{ {child.name}}
最后视图内容大家可以动手试试。
最近也试着多用这个语法去写控制器,首先写法上更偏向OO的风格。在这个ApiParetnFn
上定义不同的model。
app.controller('mainCtrl', ['$http', ApiCtrlFn]); function ApiCtrlFn(http){ this.http = http; this.name = 'XL'; } ApiCtrlFn.prototype = { reqPostFn: function(url){ this.http.get(url).success(function(data){ xxxx }) .error(function(data){ xxxx }) }, changeNameFn: function(name){ this.name = name; } } html:{ {this.name}}
在ApiParentFn.prototype
上定义不同的方法。这样可以非常好的将一些可服用的代码抽离出来。不同的控制器只需要对构造函数进行实例化,然后调用不同的原型上定义的方法就OK了。