我正在尝试使用而不是通过做来学习angularjs版本1.x。一般来说,它工作得很好,但有时,对于某些功能,我不得不使用我的代码来工作。this
$scope
var vm = this;
$scope
为此,我使用thinkster的教程:使用 Django 和 AngularJS 构建 Web 应用程序以及SitePoint的书AngularJS:从新手到忍者。
在尝试将书中的代码改编为thinkster教程中使用的代码时,我发现我不能总是使用变量vm
,例如:
在书中,示例函数的代码是:
angular.module('myApp.controllers', []);
// código eliminado para ahorrar espacio
angular.module('myApp.controllers').controller('StatsController', function($scope) {
$scope.name = 'World';
$scope.status = 'Connected';
$scope.statusColor='green';
$scope.$on('EVENT_NO_DATA', function(event, data) {
console.log('received broadcasted event');
$scope.status = data;
$scope.statusColor='red';
$scope.$emit('EVENT_RECEIVED');
}); });
我对这段代码进行了改编(根据我的理解方式),如下所示:
(function(){
'use strict';
angular.module('myEmit', [
'myEmit.controllers',
]);
angular.module('myEmit.controllers', [])
.controller('MessageController', MessageController)
.controller('StatController', StatController);
function MessageController($scope, $timeout) {
var vm = this;
vm.messages = [{
sender: 'user1',
text: 'Mensaje 1'
}];
var timer;
var count = 0;
vm.loadMessages = function(){
count++;
vm.messages.push({
sender: 'user1',
text: 'Mensaje aleatorio ' + count
});
timer = $timeout(vm.loadMessages, 2000);
if(count == 3){
$scope.$broadcast('EVENT_NO_DATA', 'Not Connected');
$timeout.cancel(timer);
}
};
timer = $timeout(vm.loadMessages, 2000);
$scope.$on('EVENT_RECEIVED', function(){
console.log('Received emitted event');
});
};
function StatController($scope) {
var vm = this;
vm.name = 'World';
vm.status = 'Connected';
vm.statusColor = 'green';
$scope.$on('EVENT_NO_DATA', function(event, data){
console.log('Received broadcast event');
vm.status = data;
vm.statusColor = 'red';
$scope.$emit('EVENT_RECEIVED');
});
};
})();
<!DOCTYPE html>
<html ng-app='myEmit'>
<head>
<meta charset="utf-8">
<title>AngularJS Events</title>
</head>
<body ng-controller="MessageController as mc">
<h4>Mensajes:</h4>
<ul>
<li ng-repeat="mensaje in mc.messages">
{{ mensaje.text }}
</li>
</ul>
<div class="" ng-controller="StatController as sc">
<h4>Estadísticas: </h4>
<div class="">
{{ mc.messages.length}} Mensaje(s)
</div>
<div class="">
Estado: <span style="color: {{ sc.statusColor}}">
{{ sc.status }}
</span>
</div>
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</html>
问题
当我尝试使用此代码时,
function StatController($scope) {
var vm = this;
vm.name = 'World';
vm.status = 'Connected';
vm.statusColor = 'green';
vm.$on('EVENT_NO_DATA', function(event, data){
console.log('Received broadcast event');
vm.status = data;
vm.statusColor = 'red';
$scope.$emit('EVENT_RECEIVED');
});
};
控制器StatController
不起作用,因为它给出了以下错误
Error: vm.$on is not a function. (In 'vm.$on', 'vm.$on' is undefined)
也就是说,它vm.$on
不是一个函数或者它是未定义的。
问
显然,当我使用时var vm = this;
,不会传递$scope
给变量vm
,因此 $on
在我的变量中无法访问类似的函数vm
。
有没有办法将函数传递$scope.on
给变量vm
?你能帮我理解this
vs是如何工作的$scope
吗?
直接回答你的问题
不,它们是不同的东西。该函数是用于发出事件的作用域的属性,它与控制器中
$on
的值无关。this
我解释。
您感到困惑的原因是因为您认为
$scope
并且this
有某种直接关系,但事实并非如此,实际上它this
只是与您的控制器相关联的另一个属性$scope
(就像$on
and$emit
)。审查:
每次创建控制器时,
$scope
都会使用方法在内部创建一个新控制器,$scopepadre.new()
这是因为它ng-controller
是使用以下配置创建的指令所说的部分
scope: true
是负责通知服务$compile
一个新的$scope
.他是如何
this
卷入这一切的?您的控制器总是被创建为某种类(这就是为什么它们应该按照约定以大写命名),就像这样
如果您阅读了运算符
new
在 javascript 中的工作方式及其对值的影响this
(检查步骤 2),您会意识到,当您以这种方式创建对象时,您添加到this
它的任何属性都将被添加到“类的实例”中“ 像这样。这纯粹是一个比较,因为 javascript 中没有类,但我认为它很好地说明了这一点。以上所有内容与
this
角度有什么关系?好吧,当你
controllerAs
以这种方式使用该选项时'MyController as foo'
,你所做的就是告诉 Angular在与元素关联'foo'
的 $scope中创建一个名为的新属性,并将新创建的控制器实例分配给该属性。理解后者很重要,范围不是控制器的特性,范围与 DOM 元素相关联,最值得注意的例子是为集合的每个元素
ng-repeat
创建一个新的指令。$scope
我们将比较传统符号与符号
controllerAs
,以便您了解区别是什么在这个例子中,在两个控制器中,一个被调用的属性
vm
是用一个空对象创建的,并且属性被添加到视图中绑定的属性。在传统方式中,您必须手动执行所有这些步骤,而在传统方式中,controllerAs
这不是必需的,因为在 javascript 中实例化对象时会创建一个新的空对象(步骤 1)。其中的属性$scope
是在与指令相同的声明中创建的。ng-controller="SampleCtrl as vm"
这个是来做什么的?
好吧,因为 angular 是 javascript,所以有时需要使用 a
.
(或所谓的“点表示法”)来引用某些对象,因为在 javascript 中,由于原型继承在 angular 中的工作方式(通常在 javascript 中),这些引用可能会丢失)。这样我们就可以确保我们引用了正确的对象。在下面的示例中,您没有使用点表示法,因此当您在子控制器中编辑属性时,它会按预期工作,但是当您尝试在其父控制器中执行此操作时,它什么也不做。
这将是正确的方法
简而言之
controllerAs
,它确保我们不会陷入这样的陷阱,我们只需要了解它是如何工作的。他$scope
仍然承担着与往常一样的职责(do$watch
,$emit
,$broadcast
, 等),并且this
他无意以任何方式取代其功能。它只是向我们保证了良好的实践,有时使我们不必在$scope
不必要的情况下进行注入。在这里,我给您留下一些文章(不幸的是英文),您可以在其中找到有关主题的更多详细信息
https://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical-inheritance-in-angularjs
http://www.egghead.io/video/DTx23w4z6Kc
https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#style-y030
你应该这样做:
我还建议您阅读一些有关 ES6 的内容,因为您可以使用角度编程生成对象类和方法,这对您来说会更容易