如何从控制器方法触发 angularjs 动画?
How to trigger an angularjs animation from a controller method?
我想从控制器方法触发 angular 动画。
我想出了一些我不满意的东西(见下面的代码)。
问题是为了让我的动画工作,我需要跟踪 $scope 变量的状态,即 $scope.shake
:
$scope.signin = function (formCtrl) {
$scope.shake = false;
if ($scope.credentials) {
signinService.signin($scope.credentials, function (status, memberRole) {
$scope.shake = false;
//TODO: necessary to check status?
if (status === 200) {
var memberType;
if (memberRole === 'ROLE_BASIC_PARENTS') {
memberType = 'parents';
}
if (memberRole === 'ROLE_BASIC_CHILDCARE_WORKER') {
memberType = 'childcare-worker';
}
$rootScope.globals = {
memberType: memberType,
authenticated: 'OK'
}
$cookies.globalsMemberType = $rootScope.globals.memberType;
$cookies.globalsAuthenticated = $rootScope.globals.authenticated;
$state.go('dashboard', {memberType: memberType});
}
},
function () {
$scope.shake = true;
});
}
else {
$scope.shake = true;
}
};
<form ng-class="{shake: shake}" name="formCtrl" ng-submit="signin(formCtrl)" novalidate>
有人可以建议更清洁的解决方案吗?
编辑 1:
这是请求的 css 代码:
@-webkit-keyframes shake {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
12.5% {
-webkit-transform: translateX(-6px) rotateY(-5deg);
transform: translateX(-6px) rotateY(-5deg);
}
37.5% {
-webkit-transform: translateX(5px) rotateY(4deg);
transform: translateX(5px) rotateY(4deg);
}
62.5% {
-webkit-transform: translateX(-3px) rotateY(-2deg);
transform: translateX(-3px) rotateY(-2deg);
}
87.5% {
-webkit-transform: translateX(2px) rotateY(1deg);
transform: translateX(2px) rotateY(1deg);
}
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@keyframes shake {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
12.5% {
-webkit-transform: translateX(-6px) rotateY(-5deg);
transform: translateX(-6px) rotateY(-5deg);
}
37.5% {
-webkit-transform: translateX(5px) rotateY(4deg);
transform: translateX(5px) rotateY(4deg);
}
62.5% {
-webkit-transform: translateX(-3px) rotateY(-2deg);
transform: translateX(-3px) rotateY(-2deg);
}
87.5% {
-webkit-transform: translateX(2px) rotateY(1deg);
transform: translateX(2px) rotateY(1deg);
}
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
.shake {
-webkit-animation: shake 400ms ease-in-out;
animation: shake 400ms ease-in-out;
}
我建议您将表单包装在指令中,并通过事件触发动画。例如在控制器中你会做:
$scope.$broadcast('FORM_ERROR');
在指令中,做一些更像
的事情
scope.$on('FORM_ERROR', function() { // code to trigger animation goes here });
对我来说把它作为一个事件来处理是有意义的,因为它有一个严格的生命周期;事件被分派,事件被处理。作用域变量会一直存在,即使它不再有任何意义。您甚至可能需要代码 'reset' 将其恢复到原始状态,以便再次触发动画,这会增加不必要的复杂性。
你会遇到另一个问题,你的动画在第一次失败后没有重置,所以连续失败不会再次执行动画。恐怕没有办法使用纯 CSS.
你首先要做的是使用Angular提供的验证服务,然后将错误动画的逻辑分离出来。
Here 是有效的解决方案,Prefix util 工厂工作得很好。
- 首先检查
form.$invalid
在你的 signin(formCtrl)
函数中,如果表单 $invalid 或来自服务的响应 returns 登录错误,然后调用一个函数来处理动画。
$scope.signin = function(form){
if(form.$invalid){
$scope.animateError();
}
};
- 更改CSS仅添加动画计时功能和持续时间。
因此,当调用
showAnimationError
函数时,它将采用表单元素,并添加值为 shake
的样式 animationName
/ webkitAnimationName
。
还记得为动画结束添加一个事件侦听器,这样您就可以清理这种样式,以便在 showAnimationError
上连续调用
/* css */
.shake {
-webkit-animation-duration: 400ms;
-webkit-animation-timing-function: ease-in-out;
animation-duration: 400ms;
animation-timing-function: ease-in-out;
}
$scope.animateError = function(){
if(!resetAnimationHandler){
addResetAnimationHandler();
}
myForm.style[prefixUtil.animationName] = 'shake';
};
希望对您有所帮助
这是我最终使用的解决方案(参见下面的代码)。它是对 Liamnes 提出的解决方案的改编。
angular.module('signin')
.controller('SigninCtrl', ['$scope', '$rootScope', '$cookies', '$state', '$animate', 'signinService', function ($scope, $rootScope, $cookies, $state, $animate, signinService) {
var setPersonalInfo = function (param) {
return signinService.setPersonalInfo(param.headers, $rootScope);
};
var goToDashboard = function (memberType) {
$state.go('dashboard', {memberType: memberType});
};
var reportProblem = function () {
$scope.formCtrl.username.$setValidity('username.wrong', false);
$scope.formCtrl.password.$setValidity('password.wrong', false);
$scope.$broadcast('SIGNIN_ERROR');
};
var resetForm = function(formCtrl){
formCtrl.username.$setValidity('username.wrong', true);
formCtrl.password.$setValidity('password.wrong', true);
};
$scope.signin = function (formCtrl) {
resetForm(formCtrl);
if (formCtrl.$valid) {
signinService.signin($scope.credentials).then(setPersonalInfo).then(goToDashboard).catch(reportProblem);
}
else {
$scope.$broadcast('SIGNIN_ERROR');
}
}
}])
.directive('shakeThat', ['$animate', function ($animate) {
return {
require: '^form',
scope: {
signin: '&'
},
link: function (scope, element, attrs, form) {
scope.$on('SIGNIN_ERROR', function () {
$animate.addClass(element, 'shake').then(function () {
$animate.removeClass(element, 'shake');
});
});
}
};
}]);
HTML:
<form shake-that name="formCtrl" ng-submit="signin(formCtrl)" novalidate>
我想从控制器方法触发 angular 动画。
我想出了一些我不满意的东西(见下面的代码)。
问题是为了让我的动画工作,我需要跟踪 $scope 变量的状态,即 $scope.shake
:
$scope.signin = function (formCtrl) {
$scope.shake = false;
if ($scope.credentials) {
signinService.signin($scope.credentials, function (status, memberRole) {
$scope.shake = false;
//TODO: necessary to check status?
if (status === 200) {
var memberType;
if (memberRole === 'ROLE_BASIC_PARENTS') {
memberType = 'parents';
}
if (memberRole === 'ROLE_BASIC_CHILDCARE_WORKER') {
memberType = 'childcare-worker';
}
$rootScope.globals = {
memberType: memberType,
authenticated: 'OK'
}
$cookies.globalsMemberType = $rootScope.globals.memberType;
$cookies.globalsAuthenticated = $rootScope.globals.authenticated;
$state.go('dashboard', {memberType: memberType});
}
},
function () {
$scope.shake = true;
});
}
else {
$scope.shake = true;
}
};
<form ng-class="{shake: shake}" name="formCtrl" ng-submit="signin(formCtrl)" novalidate>
有人可以建议更清洁的解决方案吗?
编辑 1:
这是请求的 css 代码:
@-webkit-keyframes shake {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
12.5% {
-webkit-transform: translateX(-6px) rotateY(-5deg);
transform: translateX(-6px) rotateY(-5deg);
}
37.5% {
-webkit-transform: translateX(5px) rotateY(4deg);
transform: translateX(5px) rotateY(4deg);
}
62.5% {
-webkit-transform: translateX(-3px) rotateY(-2deg);
transform: translateX(-3px) rotateY(-2deg);
}
87.5% {
-webkit-transform: translateX(2px) rotateY(1deg);
transform: translateX(2px) rotateY(1deg);
}
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@keyframes shake {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
12.5% {
-webkit-transform: translateX(-6px) rotateY(-5deg);
transform: translateX(-6px) rotateY(-5deg);
}
37.5% {
-webkit-transform: translateX(5px) rotateY(4deg);
transform: translateX(5px) rotateY(4deg);
}
62.5% {
-webkit-transform: translateX(-3px) rotateY(-2deg);
transform: translateX(-3px) rotateY(-2deg);
}
87.5% {
-webkit-transform: translateX(2px) rotateY(1deg);
transform: translateX(2px) rotateY(1deg);
}
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
.shake {
-webkit-animation: shake 400ms ease-in-out;
animation: shake 400ms ease-in-out;
}
我建议您将表单包装在指令中,并通过事件触发动画。例如在控制器中你会做:
$scope.$broadcast('FORM_ERROR');
在指令中,做一些更像
的事情scope.$on('FORM_ERROR', function() { // code to trigger animation goes here });
对我来说把它作为一个事件来处理是有意义的,因为它有一个严格的生命周期;事件被分派,事件被处理。作用域变量会一直存在,即使它不再有任何意义。您甚至可能需要代码 'reset' 将其恢复到原始状态,以便再次触发动画,这会增加不必要的复杂性。
你会遇到另一个问题,你的动画在第一次失败后没有重置,所以连续失败不会再次执行动画。恐怕没有办法使用纯 CSS.
你首先要做的是使用Angular提供的验证服务,然后将错误动画的逻辑分离出来。
Here 是有效的解决方案,Prefix util 工厂工作得很好。
- 首先检查
form.$invalid
在你的signin(formCtrl)
函数中,如果表单 $invalid 或来自服务的响应 returns 登录错误,然后调用一个函数来处理动画。
$scope.signin = function(form){
if(form.$invalid){
$scope.animateError();
}
};
- 更改CSS仅添加动画计时功能和持续时间。
因此,当调用
showAnimationError
函数时,它将采用表单元素,并添加值为shake
的样式animationName
/webkitAnimationName
。
还记得为动画结束添加一个事件侦听器,这样您就可以清理这种样式,以便在 showAnimationError
/* css */
.shake {
-webkit-animation-duration: 400ms;
-webkit-animation-timing-function: ease-in-out;
animation-duration: 400ms;
animation-timing-function: ease-in-out;
}
$scope.animateError = function(){
if(!resetAnimationHandler){
addResetAnimationHandler();
}
myForm.style[prefixUtil.animationName] = 'shake';
};
希望对您有所帮助
这是我最终使用的解决方案(参见下面的代码)。它是对 Liamnes 提出的解决方案的改编。
angular.module('signin')
.controller('SigninCtrl', ['$scope', '$rootScope', '$cookies', '$state', '$animate', 'signinService', function ($scope, $rootScope, $cookies, $state, $animate, signinService) {
var setPersonalInfo = function (param) {
return signinService.setPersonalInfo(param.headers, $rootScope);
};
var goToDashboard = function (memberType) {
$state.go('dashboard', {memberType: memberType});
};
var reportProblem = function () {
$scope.formCtrl.username.$setValidity('username.wrong', false);
$scope.formCtrl.password.$setValidity('password.wrong', false);
$scope.$broadcast('SIGNIN_ERROR');
};
var resetForm = function(formCtrl){
formCtrl.username.$setValidity('username.wrong', true);
formCtrl.password.$setValidity('password.wrong', true);
};
$scope.signin = function (formCtrl) {
resetForm(formCtrl);
if (formCtrl.$valid) {
signinService.signin($scope.credentials).then(setPersonalInfo).then(goToDashboard).catch(reportProblem);
}
else {
$scope.$broadcast('SIGNIN_ERROR');
}
}
}])
.directive('shakeThat', ['$animate', function ($animate) {
return {
require: '^form',
scope: {
signin: '&'
},
link: function (scope, element, attrs, form) {
scope.$on('SIGNIN_ERROR', function () {
$animate.addClass(element, 'shake').then(function () {
$animate.removeClass(element, 'shake');
});
});
}
};
}]);
HTML:
<form shake-that name="formCtrl" ng-submit="signin(formCtrl)" novalidate>