- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我怀疑答案是“你不能” - 但也许你可以向我展示更好的方法。
考虑这个非常简单的游戏。您单击一个按钮,它会记录您单击的次数。但最终,它会变得更加复杂 - 所以我有一个 Player
持有 timesClicked
的服务值。
angular.module( 'ClickGame', [] )
angular.module('ClickGame').factory( 'Player', function() {
var svc = {};
svc.timesClicked = 0;
return svc;
} );
angular.module('ClickGame').controller( 'MainController', [ '$scope', 'Player', function( $scope, Player ) {
// In practice, I wouldn't necessarily expose Player directly on the
// scope like this, but it makes for simpler demo code.
$scope.Player = Player;
$scope.click = function() {
Player.timesClicked++;
};
} ] );
HTML 非常不言自明:
<html ng-app="ClickGame">
<body ng-controller="MainController">
<p><button type="button" ng-click="click()">Click me!</button></p>
<p>You have clicked {{ Player.timesClicked }} times.</p>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="demo.js"></script>
</body>
</html>
到目前为止,一切都很好。这就是我遇到问题的地方:我想添加一个成就系统,当玩家完成某些目标(例如,单击按钮五次)时,该系统将向玩家授予徽章。这似乎属于它自己的组件,所以我创建了第二个名为 Achievements
的服务。 ,注入(inject) Player
:
app.factory( 'Achievements', [ 'Player', function( Player ) {
// I can't do this, because neither Achievements nor Player have a scope.
$scope.$watch( 'Player.timesClicked', function( newValue, oldValue ) {
if ( newValue >= 5 ) {
console.log( 'ACHIEVEMENT UNLOCKED: Clicked 5 Times' );
// TODO: unwatch this model, to conserve resources and prevent
// the achievement from being awarded more than once
}
} );
} ] );
看到问题了吗?
我考虑过并拒绝的方法:
使用$interval
投票Player.timesClicked
定期。由于多种原因,这显然是可怕的。
制作Achievements
指令而不是服务,因为指令确实有范围。但是,这需要我输入 <achievement>
我的 index.html 中的标记,作为实例化该范围并使其在应用程序的生命周期内保持事件状态的一种侧门方法。我已经多次看到这种方法被推荐,但感觉就像是滥用指令。必须有一种更清洁的方法。
有Player
$broadcast
每当timesClicked
时根范围上的事件递增,并在 Achievements
中监听该事件。我不喜欢这个。随着游戏变得越来越复杂,它最终会产生大量的广播噪音。不管怎样,这是旧的“让它全局化”的解决方案 - 有效,但从长远来看通常不是一个好主意:)
在成就中,使用 $rootScope.$new()
创建一个新的临时范围。 ,将 Player 附加到它,然后 $watch
那。 (或者我可以在 Player
中创建新范围,然后将该范围公开为 svc
的属性。)老实说,我不确定这是否有效 - 但当我发现自己在做这样的事情时,我怀疑我需要回溯并重构一些东西。
还有另一种我忽略的方法吗?有没有办法重构我的应用程序,以便 timesClicked
存储在更容易的地方$watch
(但仍然可以轻松地在应用程序的不同部分之间共享)?
抱歉,如果我遗漏了一些非常明显的东西;我一整天都在盯着 Angular 代码,我可能需要休息一下:)
更新:我应该提到注册 $watch
从内部MainController
行不通的。虽然我让这个演示代码保持简单,但实际应用程序是使用 ngRoute 的 SPA - 因此如果玩家导航到不同的路线,MainController 将被卸载。但成就仍应受到监督和奖励。
最佳答案
一个简单而有效的方法是使用 pub/sub 方法,但使用回调而不是事件。这是我要做的:
<html ng-app="ClickGame">
<body ng-controller="MainController">
<p><button type="button" ng-click="click()">Click me!</button></p>
<p>You have clicked {{ timesClicked }} times.</p>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="demo.js"></script>
</body>
</html>
angular.module( 'ClickGame', [] )
.factory( 'Player', function() {
var timesClicked = 0, timesClickedChangedCallbacks = [];
return {
getTimesClicked: function() { return timesClicked; },
setTimesClicked: function(val) {
timesClicked = val;
timesClickedChangedCallbacks.forEach(function(cb) { cb(val); });
},
onTimesClickedChanged: function(cb) {
if (cb && typeof cb == 'function') {
timesClickedChangedCallbacks.push(cb);
}
}
};
})
.factory( 'Achievements', [ 'Player', function( Player ) {
Player.onTimesClickedChanged(function(val) {
if ( val == 5 ) {
console.log( 'ACHIEVEMENT UNLOCKED: Clicked 5 Times' );
}
});
} ] )
.controller( 'MainController', [ '$scope', 'Player', function( $scope, Player ) {
$scope.timesClicked = Player.getTimesClicked();
$scope.click = function() {
$scope.timesClicked++;
Player.setTimesClicked($scope.timesClicked);
};
}]);
您可能还想添加一种方法来取消订阅 Player 服务中的 timesClicked 更改。
关于javascript - 我如何$watch 更改 Angular 服务的属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32388985/
你能比较一下属性吗 我想禁用文本框“txtName”。有两种方式 使用javascript,txtName.disabled = true 使用 ASP.NET, 哪种方法更好,为什么? 最佳答案 我
Count 属性 返回一个集合或 Dictionary 对象包含的项目数。只读。 object.Count object 可以是“应用于”列表中列出的任何集合或对
CompareMode 属性 设置并返回在 Dictionary 对象中比较字符串关键字的比较模式。 object.CompareMode[ = compare] 参数
Column 属性 只读属性,返回 TextStream 文件中当前字符位置的列号。 object.Column object 通常是 TextStream 对象的名称。
AvailableSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。 object.AvailableSpace object 应为 Drive 
Attributes 属性 设置或返回文件或文件夹的属性。可读写或只读(与属性有关)。 object.Attributes [= newattributes] 参数 object
AtEndOfStream 属性 如果文件指针位于 TextStream 文件末,则返回 True;否则如果不为只读则返回 False。 object.A
AtEndOfLine 属性 TextStream 文件中,如果文件指针指向行末标记,就返回 True;否则如果不是只读则返回 False。 object.AtEn
RootFolder 属性 返回一个 Folder 对象,表示指定驱动器的根文件夹。只读。 object.RootFolder object 应为 Dr
Path 属性 返回指定文件、文件夹或驱动器的路径。 object.Path object 应为 File、Folder 或 Drive 对象的名称。 说明 对于驱动器,路径不包含根目录。
ParentFolder 属性 返回指定文件或文件夹的父文件夹。只读。 object.ParentFolder object 应为 File 或 Folder 对象的名称。 说明 以下代码
Name 属性 设置或返回指定的文件或文件夹的名称。可读写。 object.Name [= newname] 参数 object 必选项。应为 File 或&
Line 属性 只读属性,返回 TextStream 文件中的当前行号。 object.Line object 通常是 TextStream 对象的名称。 说明 文件刚
Key 属性 在 Dictionary 对象中设置 key。 object.Key(key) = newkey 参数 object 必选项。通常是 Dictionary 
Item 属性 设置或返回 Dictionary 对象中指定的 key 对应的 item,或返回集合中基于指定的 key 的&
IsRootFolder 属性 如果指定的文件夹是根文件夹,返回 True;否则返回 False。 object.IsRootFolder object 应为&n
IsReady 属性 如果指定的驱动器就绪,返回 True;否则返回 False。 object.IsReady object 应为 Drive&nbs
FreeSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。只读。 object.FreeSpace object 应为 Drive 对象的名称。
FileSystem 属性 返回指定的驱动器使用的文件系统的类型。 object.FileSystem object 应为 Drive 对象的名称。 说明 可
Files 属性 返回由指定文件夹中所有 File 对象(包括隐藏文件和系统文件)组成的 Files 集合。 object.Files object&n
我是一名优秀的程序员,十分优秀!