我正在构建一个包含动画的应用程序,我需要它才能更好地工作。我希望能够以指定的动画间隔浏览一系列div并一次显示一个div。我希望每个系列都有自己的速度和自己的div。
这是我到目前为止的内容(也在下面复制):http://jsfiddle.net/ollerac/shkq7/
基本上,我正在寻找一种方法将setInterval放在animatedBox的属性上,这样我就可以创建一个带有自定义属性的新animatedBox。但每次我尝试这样做都会打破。
HTML
<div ng-app ng-controller="BoxController">
<div class="layer" ng-repeat="layer in animatedBox.layers" ng-style="{ 'backgroundColor': layer.color}" ng-show="layer == animatedBox.selectedLayer"></div>
</div>
的 JAVASCRIPT
function buildBox () {
return {
color: '#' + (Math.random() * 0xFFFFFF << 0).toString(16)
}
}
function BoxController ($scope) {
$scope.animatedBox = {
layers: [],
selectedLayer: null
};
for (var i = 0; i < 5; i++) {
$scope.animatedBox.layers.push(buildBox());
}
var i = -1;
setInterval(function () {
$scope.$apply(function() {
i++;
if (i < $scope.animatedBox.layers.length) {
$scope.animatedBox.displayThisLayer = $scope.animatedBox.layers[i];
} else {
i = 0;
$scope.animatedBox.selectedLayer = $scope.animatedBox.layers[i];
}
});
}, 500);
}
的 CSS
.layer {
width: 30px;
height: 30px;
position: absolute;
}
*更新*
以下是我想做的事情:
更新了jsFiddle:http://jsfiddle.net/ollerac/shkq7/2/
function buildBox () {
return {
color: '#' + (Math.random() * 0xFFFFFF << 0).toString(16)
}
}
function BoxController ($scope) {
$scope.animatedBox = {
layers: [],
selectedLayer: null,
selectedLayerIndex: -1,
updateSelectedLayer: function () {
var self = this;
if (self.layers.length) {
$scope.$apply(function() {
self.selectedLayerIndex++;
if (self.selectedLayerIndex < self.layers.length) {
self.selectedLayer = self.layers[self.selectedLayerIndex];
} else {
self.selectedLayerIndex = 0;
self.selectedLayer = self.layers[self.selectedLayerIndex];
}
});
}
}
};
for (var i = 0; i < 5; i++) {
$scope.animatedBox.layers.push(buildBox());
}
setInterval(function () {
$scope.animatedBox.updateSelectedLayer();
}, 500);
}
现在,对象更新了自己的selectedLayer
属性。 但是我仍然需要调用单独调用更新的setInterval以使其更新。但我希望对象能够自我更新并完全独立。你能想出一个很好的方法来做到这一点,因为我真的很擅长......
我想这更像是一个普通的javascript问题,但我认为可能有一种Angular方式来处理这种情况,比如可能使用指令或某些东西是合适的。
任何建议都非常赞赏。
答案 0 :(得分:2)
你是对的,我相信指令是正确的解决方案。 (顺便说一下,这个很有趣。)
当接近这样的问题时,我通常首先编写我希望我能写的HTML和控制器,如果一切都已经有效的话。对于这个例子,这是我最终的结果。
<div ng-controller="BoxController">
<div animated-boxes="colors"></div>
</div>
app.value('randomColor', function() {
var red = Math.floor(Math.random() * 255);
var green = Math.floor(Math.random() * 255);
var blue = Math.floor(Math.random() * 255);
return "rgb(" + red + "," + green + "," + blue + ")";
});
app.controller('BoxController', function($scope, randomColor) {
$scope.colors = [ randomColor(), randomColor() ];
});
这里,控制器仅 负责设置范围内的一些基本数据 - 一组颜色; DOM 非常简单,只将该数组传递给名为animated-boxes
的东西。 randomColor
已移至服务中,因此可以更轻松地重复使用和测试。 (我也稍微改了一下,因此不会导致错误的十六进制值。)
现在,唯一尚未发挥作用的部分就是这个名为animated-boxes
的东西。每当您想要与DOM交互时,或者在使用HTML属性时触发某些行为,我们都会转向指令。
我们将定义我们的指令,注入$timeout
服务,因为我们知道我们想要做基于计时器的东西。该指令的结果只是一个对象。
app.directive('animatedBoxes', function($timeout) {
return {
};
});
由于我们希望指令是自包含的并且不会弄乱它所包含的外部范围,我们将给它一个隔离范围(有关更多信息,请参阅directive docs,但基本上这只是意味着除了通过我们指定的变量之外,我们的范围没有附加到指令所在的范围。)
由于我们希望通过HTML属性访问传递给指令的值,因此我们将在该值上设置双向范围绑定;我们称之为colors
。
app.directive('animatedBoxes', function($timeout) {
return {
scope: {
colors: '=animatedBoxes'
}
};
});
我们将为其提供一个简单的模板,该模板循环遍历colors
,并为每种颜色输出div
s之一。我们的ng-show
表示只有在范围值div
等于selected
时才会显示$index
,ng-repeat
是{{1}的当前迭代的数组索引循环。
app.directive('animatedBoxes', function($timeout) {
return {
scope: {
colors: '=animatedBoxes'
},
template: "<div><div class='layer' ng-repeat='color in colors' " +
"ng-style='{backgroundColor: color}' ng-show='selected == $index'>" +
"</div></div>"
};
});
现在为链接函数 - 将处理指令逻辑的函数。首先,我们想要跟踪我们正在展示哪个盒子;在我们的ng-show
中,我们使用了selected
。我们还想跟踪我们有多少箱子;我们将在我们的指令范围内使用$watch
来跟上这一点。
link: function(scope, elem, attrs) {
scope.selected = 0;
var count = 0;
scope.$watch('colors', function(value) {
// whenever the value of `colors`, which is the array
// of colors passed into the directive, changes, update
// our internal count of colors
if (value) count = value.length;
else count = 0; // if `colors` is falsy, set count to 0
}, true); // `true` ensures we watch the values in the array,
// not just the object reference
}
最后,我们需要经常循环每个盒子。我们将使用$timeout
执行此操作,setTimeout
是$apply
的一个版本,其中包含范围var nextBox = function() {
if (scope.selected >= count - 1) scope.selected = 0;
else scope.selected++;
// recursively use `$timeout` instead of `setInterval`
$timeout(nextBox, 500);
};
// kick off the directive by launching the first `nextBox`
nextBox();
调用(它执行其他一些操作,但我们现在不关心它)。
app.directive('animatedBoxes', function($timeout) {
return {
scope: {
colors: '=animatedBoxes'
},
template: "<div><div class='layer' ng-repeat='color in colors' " +
"ng-style='{backgroundColor: color}' ng-show='selected == $index'>" +
"</div></div>",
link: function(scope, elem, attrs) {
scope.selected = 0;
var count = 0;
scope.$watch('colors', function(value) {
if (value) count = value.length;
else count = 0;
}, true);
var nextBox = function() {
if (scope.selected >= count - 1) scope.selected = 0;
else scope.selected++;
$timeout(nextBox, 500);
};
nextBox();
}
};
});
如果你把整个指令放在一起,你最终会得到这个代码(删除注释):
colors
一个完整的工作示例,包括注释和一些调试区域,您可以在其中查看colors
的值并与之交互(以便您可以看到该指令如何响应控制器中的更改) :http://jsfiddle.net/BinaryMuse/g6A6Y/
现在您已经拥有了这个,请考虑尝试应用这些知识,以允许指令通过DOM传递它具有可变速度,就像我们对{{1}}所做的那样。这是我的结果:http://jsfiddle.net/BinaryMuse/cHHKn/