3

我想从控制器方法触发角度动画。

我想出了一些我不满意的东西(见下面的代码)。

问题是,为了让我的动画正常工作,我需要跟踪 $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;
}
4

3 回答 3

4

我建议您将表单包装在指令中,并通过事件触发动画。例如在控制器中你会做:

$scope.$broadcast('FORM_ERROR');

在指令中,做一些更像

scope.$on('FORM_ERROR', function() { // code to trigger animation goes here });

对我来说把它当作一个事件来处理是有意义的,因为它有一个严格的生命周期;事件被调度,事件被处理。范围变量会一直存在,即使它不再具有任何意义。您甚至可能需要代码将其“重置”回其原始状态,以便可以再次触发动画,这会增加不必要的复杂性。

于 2015-05-10T17:51:16.443 回答
1

您将遇到另一个问题,您的动画在第一次失败后没有重置,因此连续失败不会再次执行动画。恐怕没有办法使用纯 CSS 来做到这一点。

你应该首先使用Angular提供的验证服务,然后分离错误动画的逻辑。

是有效的解决方案,Prefix util工厂工作得很好。

  • 首先检查form.$invalid你的signin(formCtrl)函数内部,如果表单是 $invalid 或者服务的响应返回登录错误,然后调用一个处理动画的函数。

  $scope.signin = function(form){
    if(form.$invalid){
      $scope.animateError();
    }
  };

  • 将 CSS 更改为仅添加动画计时功能和持续时间。因此,当showAnimationError调用该函数时,它将采用 form 元素,并添加样式animationName/webkitAnimationName和 value shake

还记得为动画结束添加一个事件监听器,这样你就可以清理这个样式,用于连续调用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';
};

我希望这可以帮助你

于 2015-05-11T02:51:45.297 回答
0

这是我最终使用的解决方案(请参见下面的代码)。这是对 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>
于 2015-05-11T17:24:20.523 回答