Angular.js 动画
Angular.js animations
我有一个带有 ng-repeat
的块,其定义如下:
<div ng-show="isPageSelected(item.page)" class="block" ng-repeat="item in data">
...
</div>
目前我可以通过单击某些元素在这些块之间切换。正如您可能已经猜到的那样,它通过 ng-show="isPageSelected(item.page)"
工作。一切正常,但它们会立即切换,我想添加一个动画,一个简单的淡出 in/fade 就可以了。
因此,不再选择的块应该淡出,当它消失时,新块应该淡入。当我使用 ngAnimate
时,它们同时淡入和淡出。我需要第一个块完全消失并用 display: none;
隐藏,完成后下一个块应该出现并淡入。使用 jQuery 时这是一个相当简单的任务,但我如何优雅地做到这一点Angular.js?
我强烈怀疑 Angular.js 对于具有复杂动画的网站来说并不是一个好的选择。
编辑:为了简化我的问题,我需要做的就是
- 点击按钮启动动画;
- 动画完成后,更改模型;
- 运行另一个动画。
由于我需要在动画之后更改模型,因此可能无法通过纯 CSS 来完成。我知道在 angular 中的特定元素上触发动画的唯一方法是创建指令,将作用域变量传递到指令中,在指令中为该变量创建观察器,然后从控制器更改变量:
<div animation="page"></div>
app.directive('animation', function(){
return {
scope: { page: '=animation' },
link: function(scope, element){
scope.$watch('page', function(newVal){
...
});
}
};
});
我想它会起作用,但为此创建一个指令似乎真的很臃肿。另外,仅当动画完成后,我如何使用这种方法更改 $scope.page
?添加另一个范围变量只是为了触发动画并在动画完成时以某种方式更改 $scope.page
?使用 ngFx
模块可以做到这一点,但它所需要的代码量实在是太荒谬了。在这一点上,我认为向控制器添加 jQuery 动画将是解决它的更漂亮的方法。
编辑:这就是 jQuery 动画的样子:
$scope.changePage = function(page) {
$('.block').animate({opacity: 0}, 500, function(){
$scope.page.id = page;
$scope.$apply();
$(this).animate({opacity: 1}, 500);
});
};
它工作正常,不像指令那样冗长,但我必须使用 CSS 选择器,感觉非常 "unangular"。你们在处理动画时是否使用类似的东西?
编辑:使用 ngFx
:
有点类似的方法
<div ng-hide="switchPageAnimation"
class="block fx-fade-normal fx-speed-300 fx-trigger">
在控制器中:
$scope.switchPageAnimation = false;
$scope.changePage = function(page) {
if($scope.page.id === page || $scope.switchPageAnimation) return;
$scope.switchPageAnimation = true;
$scope.$on('fade-normal:enter', function(){
$scope.page.id = page;
$scope.switchPageAnimation = false;
});
};
我没有使用 CSS 选择器,但它看起来仍然很糟糕。我必须为动画定义一个范围变量,然后检查动画是否已经在运行。我觉得我错过了一些非常明显的东西。
您可以将您想要的过渡添加到元素的 CSS class 到 show/hide:
animate-show.ng-hide-add.ng-hide-add-active,
.animate-show.ng-hide-remove.ng-hide-remove-active {
-webkit-transition: all linear 0.5s;
transition: all linear 0.5s;
}
在此处查看更多信息:
https://docs.angularjs.org/api/ng/directive/ngShow#example
事实上,使用 CSS 是 'right' 的方法,尽管它可能感觉不 angular。
也许这会对您有所帮助,并且在您的情况下没有必要等待动画完成。如果您的页面具有 css position: absolute 并且位于具有 position: relative 的容器中,那么它们共享相同的位置并且在动画时不会显示在另一个下方。使用此设置,您可以淡入淡出或延迟显示动画
转换延迟:
.container1{
position: relative;
height:400px;
}
.block1{
position:absolute;
}
.block1.ng-hide-add-active {
display: block!important;
-webkit-transition: 2s linear all;
transition: 2s linear all;
}
.block1.ng-hide-remove-active {
display: block!important;
-webkit-transition: 2s linear all;
transition: 2s linear all;
-webkit-transition-delay: 2s;
transition-delay: 2s;
}
.block1.ng-hide {
opacity: 0;
}
编辑:
如果您在 ng-repeat 中使用过滤器而不是 ng-show 来显示这样的选定页面
<div class="block1" ng-repeat="item in data | filter:isPageSelected">
然后从 dom 和 angular 添加和删除页面 添加 类 ng-enter 、 ng-enter-active 和 ng-leave ng-leave-active
但是动画可以定义类似见fiddle:http://jsfiddle.net/o944epzy/
实际上,您必须使用 CSS 来显示和隐藏 ng-repeat 中的元素;
当你使用 ngAnimate 时,不要忘记将它注入到你的模块中。
.module('myModule', [ 'ngAnimate', ...
当你将 add/remove 来自你的 ng-repeat 数据源的元素时这样做。
Angular 将添加和删除 class ng-enter, ng-leave
。
Here 是一个很好的关于 ngAnimate 动画的教程。
在您自己的情况下,您想更改页面。我建议你有太多的项目不能一次显示。
您可以在您的作用域中声明两个变量:
$scope.elemByPage = 5;
$scope.page = 0;
$scope.nbPages = ...; // I let you do the maths ;)
然后在您的模板中,您可以简单地执行以下操作:
<div class="my-repeat-item" data-ng-repeat="item in data | pager:page:elemByPage">
{{item.xxx}}
</div>
此模板将仅根据页码和每页元素数显示所需的项目。
Pager 是一个简单的过滤器,它可以解决问题
.filter('pager',[function(){
return function(items, page, nbElemByPage) {
if(!nbElemByPage || nbElemByPage < 1) {
return items;
}
var nbPages = Math.floor(items.length/nbElemByPage);
if(nbPages<1) {
return items;
}
var startIndex = page*nbElemByPage;
return items.splice(startIndex, nbElemByPage);
};
}])
现在您只需使用按钮即可浏览您的项目
<button data-ng-click="page = page - 1"/>Prev page</button>
<button data-ng-click="page = page - 1"/>Next page</button>
最后,您想要在新项目上添加淡入淡出动画,因此请在您的 css 项目 class 之后声明这些 classes(此处 my-repeat-item
)
.my-repeat-item.ng-enter {
transition: 0.6s ease all;
opacity:0;
}
.my-repeat-item.ng-enter.ng-enter-active {
opacity:1;
}
删除项目时,您可以通过将 enter
替换为 leave
来执行相同的操作。
希望它能回答您的问题。
实际上,您必须使用 CSS 来显示和隐藏 ng-repeat 中的元素;当你使用 ngAnimate 时,不要忘记将它注入到你的模块中。
我有一个带有 ng-repeat
的块,其定义如下:
<div ng-show="isPageSelected(item.page)" class="block" ng-repeat="item in data">
...
</div>
目前我可以通过单击某些元素在这些块之间切换。正如您可能已经猜到的那样,它通过 ng-show="isPageSelected(item.page)"
工作。一切正常,但它们会立即切换,我想添加一个动画,一个简单的淡出 in/fade 就可以了。
因此,不再选择的块应该淡出,当它消失时,新块应该淡入。当我使用 ngAnimate
时,它们同时淡入和淡出。我需要第一个块完全消失并用 display: none;
隐藏,完成后下一个块应该出现并淡入。使用 jQuery 时这是一个相当简单的任务,但我如何优雅地做到这一点Angular.js?
我强烈怀疑 Angular.js 对于具有复杂动画的网站来说并不是一个好的选择。
编辑:为了简化我的问题,我需要做的就是
- 点击按钮启动动画;
- 动画完成后,更改模型;
- 运行另一个动画。
由于我需要在动画之后更改模型,因此可能无法通过纯 CSS 来完成。我知道在 angular 中的特定元素上触发动画的唯一方法是创建指令,将作用域变量传递到指令中,在指令中为该变量创建观察器,然后从控制器更改变量:
<div animation="page"></div>
app.directive('animation', function(){
return {
scope: { page: '=animation' },
link: function(scope, element){
scope.$watch('page', function(newVal){
...
});
}
};
});
我想它会起作用,但为此创建一个指令似乎真的很臃肿。另外,仅当动画完成后,我如何使用这种方法更改 $scope.page
?添加另一个范围变量只是为了触发动画并在动画完成时以某种方式更改 $scope.page
?使用 ngFx
模块可以做到这一点,但它所需要的代码量实在是太荒谬了。在这一点上,我认为向控制器添加 jQuery 动画将是解决它的更漂亮的方法。
编辑:这就是 jQuery 动画的样子:
$scope.changePage = function(page) {
$('.block').animate({opacity: 0}, 500, function(){
$scope.page.id = page;
$scope.$apply();
$(this).animate({opacity: 1}, 500);
});
};
它工作正常,不像指令那样冗长,但我必须使用 CSS 选择器,感觉非常 "unangular"。你们在处理动画时是否使用类似的东西?
编辑:使用 ngFx
:
<div ng-hide="switchPageAnimation"
class="block fx-fade-normal fx-speed-300 fx-trigger">
在控制器中:
$scope.switchPageAnimation = false;
$scope.changePage = function(page) {
if($scope.page.id === page || $scope.switchPageAnimation) return;
$scope.switchPageAnimation = true;
$scope.$on('fade-normal:enter', function(){
$scope.page.id = page;
$scope.switchPageAnimation = false;
});
};
我没有使用 CSS 选择器,但它看起来仍然很糟糕。我必须为动画定义一个范围变量,然后检查动画是否已经在运行。我觉得我错过了一些非常明显的东西。
您可以将您想要的过渡添加到元素的 CSS class 到 show/hide:
animate-show.ng-hide-add.ng-hide-add-active,
.animate-show.ng-hide-remove.ng-hide-remove-active {
-webkit-transition: all linear 0.5s;
transition: all linear 0.5s;
}
在此处查看更多信息: https://docs.angularjs.org/api/ng/directive/ngShow#example
事实上,使用 CSS 是 'right' 的方法,尽管它可能感觉不 angular。
也许这会对您有所帮助,并且在您的情况下没有必要等待动画完成。如果您的页面具有 css position: absolute 并且位于具有 position: relative 的容器中,那么它们共享相同的位置并且在动画时不会显示在另一个下方。使用此设置,您可以淡入淡出或延迟显示动画
转换延迟:
.container1{
position: relative;
height:400px;
}
.block1{
position:absolute;
}
.block1.ng-hide-add-active {
display: block!important;
-webkit-transition: 2s linear all;
transition: 2s linear all;
}
.block1.ng-hide-remove-active {
display: block!important;
-webkit-transition: 2s linear all;
transition: 2s linear all;
-webkit-transition-delay: 2s;
transition-delay: 2s;
}
.block1.ng-hide {
opacity: 0;
}
编辑: 如果您在 ng-repeat 中使用过滤器而不是 ng-show 来显示这样的选定页面
<div class="block1" ng-repeat="item in data | filter:isPageSelected">
然后从 dom 和 angular 添加和删除页面 添加 类 ng-enter 、 ng-enter-active 和 ng-leave ng-leave-active
但是动画可以定义类似见fiddle:http://jsfiddle.net/o944epzy/
实际上,您必须使用 CSS 来显示和隐藏 ng-repeat 中的元素; 当你使用 ngAnimate 时,不要忘记将它注入到你的模块中。
.module('myModule', [ 'ngAnimate', ...
当你将 add/remove 来自你的 ng-repeat 数据源的元素时这样做。
Angular 将添加和删除 class ng-enter, ng-leave
。
Here 是一个很好的关于 ngAnimate 动画的教程。
在您自己的情况下,您想更改页面。我建议你有太多的项目不能一次显示。
您可以在您的作用域中声明两个变量:
$scope.elemByPage = 5;
$scope.page = 0;
$scope.nbPages = ...; // I let you do the maths ;)
然后在您的模板中,您可以简单地执行以下操作:
<div class="my-repeat-item" data-ng-repeat="item in data | pager:page:elemByPage">
{{item.xxx}}
</div>
此模板将仅根据页码和每页元素数显示所需的项目。 Pager 是一个简单的过滤器,它可以解决问题
.filter('pager',[function(){
return function(items, page, nbElemByPage) {
if(!nbElemByPage || nbElemByPage < 1) {
return items;
}
var nbPages = Math.floor(items.length/nbElemByPage);
if(nbPages<1) {
return items;
}
var startIndex = page*nbElemByPage;
return items.splice(startIndex, nbElemByPage);
};
}])
现在您只需使用按钮即可浏览您的项目
<button data-ng-click="page = page - 1"/>Prev page</button>
<button data-ng-click="page = page - 1"/>Next page</button>
最后,您想要在新项目上添加淡入淡出动画,因此请在您的 css 项目 class 之后声明这些 classes(此处 my-repeat-item
)
.my-repeat-item.ng-enter {
transition: 0.6s ease all;
opacity:0;
}
.my-repeat-item.ng-enter.ng-enter-active {
opacity:1;
}
删除项目时,您可以通过将 enter
替换为 leave
来执行相同的操作。
希望它能回答您的问题。
实际上,您必须使用 CSS 来显示和隐藏 ng-repeat 中的元素;当你使用 ngAnimate 时,不要忘记将它注入到你的模块中。