让 Angular 应用动起来!

【编者按】本文主要通过生动的实例,介绍为 Angular 应用添加动画的原理与过程。文章系国内 ITOM 管理平台 OneAPM 编译呈现。

我们知道,Angular 应用在更新 DOM 时,会直接将元素转储为视图而没有过渡,其默认的用户体验并不和谐。

不过,好消息是,Angular 附带了对动画的大力支持;当然,坏消息是它可能和预期效果有所出入。Angular 并不能制作动画,但是为用户的自定义动画提供了许多组件。

理解 $animate 和 ngAnimate 模块

在非 Angular Javascript 应用中更新 DOM 时,程序员会无意识地在动画中加入自定义成分;但是,在 Angular 应用中,经常会使用内置指令,而不是在DOM上直接更改。

因此,开发者要怎么做呢?

如果不使用 Angular,怎样将动画添加到Web应用中呢?
你需要:

  • 定义动画开始和结束的风格;
  • 添加或更改某个元素,并将其设置为起始风格;
  • 设置动画的结束风格;

通常,你会使用Javascript或CSS来完成以上步骤。

当往 Angular 应用添加动画时,当然也要遵循这个模式,但是却以 Angular 特有的方式——动画代码完全从指令代码分离出来。

这是很好的方法

Angular 的内置指令是预先为动画设定的。这就意味着,你可以使用许多通过 CSS 类或 Javascript 代码就能调用的动画“事件”。这些事件与元素或类的添加/删除相对应。

这可能听起来有点怪,但其好处是你可以创建自定义指令,然后让这些指令的终端用户自定义他们的动画。

代码复用 FTW

这正是 Angular 设计指令的特有方式。这样一来,由于 Angular 没有预定义动画,开发和设计人员就可以选择自己喜欢的方式来创建动画,比如利用CSS过渡/动画或JavaScript库。

构建自己的指令

如果自己写一个简单的自定义指令并做成动画,更有助于理解各个部分如何协同工作;然后再回过头来,更容易理解内置指令的工作模式。

下面是一个简单的指令,旨在无动画支持时隐藏元素:

app.controller("example", function($scope){
    $scope.awesome = false;
});

app.directive("myHide", function(){
    return {
        restrict: 'A',
        link: function(scope, elem, attrs){
            scope.$watch(attrs.myHide, function(value){
                if (value) {
                    elem.addClass("hide");
                } else {
                    elem.removeClass("hide");
                }
            });
        }
    };
});

myHide 指令关注着一个表达式的取值(本例中 ‘awesome’ 的值),当表达式判定结果为真时,在元素中添加类;若为假,则移除类。因为类集显示设为 none,所以当表达式为真时 myHide 元素为隐藏状态。

<div class="myHideExample" ng-controller="example">
    <div class="message">
      <p my-hide="awesome">Hide this text if awesome</p>
    </div>
    <button class="button" ng-click="awesome = !awesome">Toggle awesomeness</button>
  </div>

这有动画效果,但没有过渡,只是弹出进出。

不借助 $animate 时,为指令添加动画

既然 Angular 动画只是在关键事件元素中添加CSS类(或通过触发Javascript回调函数,我们稍后将会介绍),再加上Javascript 只能添加或删除 CSS 类的约束条件,我们可以为指令添加一个简单的渐淡动画。因为Javascript 并不了解动画过程,所以若不定义CSS 类,指令虽然可以执行,但不会产生动画效果。

$animate的工作原理

myHide 动画能使元素的不透明度从1淡化到0(当状态切换时则反之)。在动画结束时,显示应该设置为none。

这就有一个有趣的问题,因为只有动画结束时才能将显示设为none——否则整个动画运行时,该元素不可见。因此,需要一个CSS类代表过渡/动画,还需要另一个CSS类,方便在所有事情完成后将显示设为none。

到目前为止,CSS 该是什么样子?

//the final state
.hide {
    display: none;
}
//the animation
.hide-add-start {
    transition: opacity 1s;
    opacity: 0;
}

接着,再在适当的时候,把指令中的几行 Javascript 语句加入到类中。

/ add this first to start the animation
elem.addClass("hide-add-start");
setTimeout(function() {
    // add the hide class after animation is finished
    elem.addClass("hide");
    // clean up
    elem.removeClass("hide-add-start");
}, 1000);

所以 .hide-add-start 类添加了过渡效果和最终值,过渡完成之后再添加 .hide 类以便将显示设为 none。

用于移除和绘制 hide类动画的 CSS

. hide-remove {
    transition: opacity 1s;
    opacity: 0;
}
.hide-remove-active {
    opacity: 1;
}

在实现移除 .hide 类的动画效果时,第一步是将不透明度设为0;否则,该元素会直接弹出,不存在任何动画效果。

为了创建不透明度从0到1过渡效果,需要另一个类来定义结束状态。因此,需要一个类来定义起始状态和过渡/动画,另一个类来定义结束状态的动画。

Javascript 代码与添加.hide类的过程几乎一样,但是现在需要两个类。

elem.addClass("hide-remove");
elem.removeClass("hide");
  // cause a reflow
elem[0].offsetHeight;
elem.addClass("hide-remove-active");
setTimeout(function(){
    elem.removeClass("hide-remove");
    elem.removeClass("hide-remove-active");
}, 1000);

移除.hide类和添加.hide-remove-active类之间的那一行代码会引起回流。如果没有那行,浏览器就不能应用过渡效果,造成元素直接弹出。

现在,终于知道了 $animate 和 ngAnimate 的工作过程

为指令添加动画并不像添加和删除一个类那样简单。你需要知道动画什么时候开始、什么时候结束,开始和结束的状态,知道后需要 JavaScript 协调这一切,这也正是 $animate 的作用内容。

$Animate 服务有添加/删除类和元素的方法。当在指令中使用这些方法时,针对制作动画的元素,Angular 会自动添加和删除类。

它还能在正确的时间添加或删除类,因此你可以自定义开始和结束状态。不仅如此,Angular还能从CSS中读取时间,以便在同一位置定义时间。

重写指令以利用$animate

$animate 服务有几种用于添加/删除/移动元素或添加/删除类的方法。其理念是使用这些方法而不是直接操作DOM,并用 Angular 触发 Javascript 动画,或添加/删除额外需要的CSS类。

你无需加载 ngAnimate 就可以注入 $animate 服务,而且在不触发动画的情况下各个部分都能正常工作。这就太好了,因为即使未定义或使用动画,你也可以创建正常工作的自定义指令。

如果希望动画被激活,就必须下载 ng-animate 模块 Javascript,并把ng-animate 模块列入你的应用程序,如下所示:

var app = angular.module('animations', ['ngAnimate']);

有了 $animate,myHide 指令的新版本如下所示:

app.directive("myHide", function($animate){
    return {
        restrict: 'A',
        link: function(scope, elem, attrs){
            scope.$watch(attrs.myHide, function(value){
                if (value) {
                    $animate.addClass(elem, "hide");
                } else {
                    $animate.removeClass(elem, "hide");
                }
            });
        }
    };
});

CSS将略有不同。除了要添加到元素中的实际的类,addClass 和 removeClass 语句还添加了两个附加的类:其中一个用于动画和起始风格,另一个用于结束风格。这两个附加类在结束时都会被删除。

添加CSS类需遵循命名约定。因此,在本例中,你添加的类是 “hide” ,则 $animate 会在应定义动画和起始风格的位置再添加一个 “hide-add” 类,同时在任意结束风格的位置添加一个 “hide-add-active” 类。

以下是一个说明文档的截图,其中说明了需要创建哪些额外的类,命名约定和每个类的添加时间。

根据以上规则,CSS 可如下所示:

. .hide-add {
    display: block;
    transition: opacity 1s;
    opacity: 1;
}
.hide-add-active {
    opacity: 0;
}
.hide-remove {
    transition: opacity 1s;
    display: block;
    opacity: 0;
}
.hide-remove-active {
    opacity: 1;
}

“hide-add” 类将显示值设为 “block”,因为 “hide” 类在同一时间加入,并设置显示为 “none”,而这不是我们想要的。

即使 $animate 指令只能添加一个类,但是它同样支持 DOM 上用于添加/删除CSS类的其他操作方法,因此你可以在 Angular 应用上实现几乎所有动画。

大多数内置指令都使用 $animate 进行DOM操作,这意味着你同样可以为它们实现动画。若想了解使用 $animate 的内置指令列表,可点击此处

ngAnimate 和 Javascript 动画

你也可以使用 Javascript 动画而不是 CSS 动画/过渡。下面的实例使用了TweenMax 库,不过你也可以使用其他自己喜欢的库。

除了添加 CSS 类,$animate 服务也能触发你在 APP 中定义的任何JavaScript动画。

app.directive("myHideJs", function($animate){
    return {
        restrict: 'A',
        link: function(scope, elem, attrs){
            scope.$watch(attrs.myHideJs, function(value){
                if (value) {
                    $animate.addClass(elem, "hide-js");
                } else {
                    $animate.removeClass(elem, "hide-js");
                }
            });
        }
    };
});

app.animation('.hide-js-animated', function(){
    return {
        addClass: function(element, className){
            TweenMax.to(element, 1, {
                'opacity': 0
                });
        },
        removeClass: function(element, className){
            TweenMax.to(element, 1, {
                'opacity': 1
            });
        }
    }
});

可以看到,在该指令使用 $animate 服务和用其进行 CSS 动画的方式一样,并无区别。

指令下面是动画,使用简单、单一的 CSS 类选择器来命名。使用该动画的元素必须包括这个类,否则将无法进行动画操作。

由动画调用返回的对象定义了两个属性,addClass 和 removeClass。定义这两个属性则是因为指令中用到了addClass 和 removeClass。如果元素从指令中移除或添加,则定义为 ‘leave’ 和 ‘enter’ 属性。

你可以在”由JavaScript定义的动画”部分查看完整的事件列表
下面是使用JavaScript动画的Angular模板。请注意,最终要作动画的元素中的类,要与Angular应用所定义的动画名称匹配。

<div class="myHideExample" ng-controller="example">
  <div class="message">
    <p my-hide-js="awesome" class="hide-js-animated">Hide this text if awesome</p>
  </div>
  <button class="button" ng-click="awesome = !awesome">Toggle awesomeness</button>
</div>

实现内置指令的动画

大多数内置指令都使用 $animate,正如 myHide指令。下面为ngHide代码:

var ngHideDirective = ['$animate', function($animate) {
  return {
    restrict: 'A',
    multiElement: true,
    link: function(scope, element, attr) {
      scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
        // The comment inside of the ngShowDirective explains why we add and
        // remove a temporary class for the show/hide animation
        $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
          tempClasses: NG_HIDE_IN_PROGRESS_CLASS
        });
      });
    }
  };
}];

是不是很眼熟?这是因为它几乎和你这段时间一直在看的 myHide 指令完全一样。不过也有少许不同,主要是ngHide使用三元运算符来代替 if / else,从而确定调用 addClass还是removeClass。

再看看其他内置指令,就会看到对 $animate的调用。每个指令的说明文档记录了可以在动画中使用的事件列表。之后,就只是创建CSS动画还是JavaScript动画,以及将所有名称都与命名约定相匹配的问题。

厌倦了 Angular的“魔力”?

Angular的学习曲线虽然并不简单,但归根结底还是值得我们学习的。不过, Angular 充满了奇怪的新概念,而且最终的结果有时看起来简直不可思议。

所有的框架都坚持己见,Angular 也不例外。问题在于,通过 Angular可以创建运行简单的应用程序;但是,在了解它之前,你可能会遇到许多难以检测和调试的问题。这时候,借助 OneAPM 提供的检测工具,就能轻松解决这些难题。

本文转自 OneAPM 官方博客

原文链接:http://www.planningforaliens.com/angular/animate-your-angular-application/

时间: 2024-09-16 02:10:16

让 Angular 应用动起来!的相关文章

利用CSS3在Angular中实现动画_AngularJS

废话不多说了,直接给大家贴实例代码. 直接看例子: <!DOCTYPE HTML> <html ng-app="myApp"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>ngAnimate插件1</title> <script type=&quo

给angular加上动画效遇到的问题总结_AngularJS

加入"动效"是让用户对应用的行为进行感知的一种有效手段."列表"是应用中最常使用的一种界面形式,经常会有添加行,删除行,移动行这些操作.设想添加的操作很简单,删除时从大到小,然后消失:添加时从小到大:移动就是先删除再添加.感觉上并不复杂,应该利用CSS的transition就能搞定,可是实际做起来发现有不少问题要处理,下面一一道来. 来些简单的测试 1.最初的版本 <div class='list'> <div class='row-1'>r

动易系统九个常见的错误原因分析及解决方法

错误|解决 错误提示:ADODB.Recordset 错误 '800a0cc1'Item cannot be found in the collection corresponding to the requested name or ordinal./index.asp,行15 错误原因:服务器上安装动易组件最新组件,但网站系统是用的4.0,系统没有找到相应的字段.动易组件从4.02开始向下兼容,但不兼容4.0.解决方法:请在升级网站系统至最新版本. =====================

PS教你轻松6步把GIF动效图嵌入到手机模版

  很多设计师可以做出动效Gif,但不知道如何嵌入到模版里如下图这样展示: 昨天有个设计妹子问我这个问题,既然是妹子那我就花五分钟教你嵌入Gif到模板. 1. 首先利用Hype 或者Pixate做出一张动态的Gif 图如下: (注:AE 可以保存成.Mp4 ,Pixate 可以录屏,Hype可以直接转换成Gif,视频格式可以通过软件或Photoshop转换成Gif ,总之就是做出你想要的动效Gif) 2. 用Photoshop打开Gif 图片,窗口-时间轴面板,单击选择将帧拼合到图层,这样就把所

PS动漫手绘风照片制作三步曲

  动漫手绘风照片制作三步曲:1.前期准备2.后期PS制作以及素材的准备3.润色做光效做质感,比较多的实用技巧,换背景.抠图.调色,值得借鉴学习 分类: PS图片处理

动易系统解决IE8网站后台编辑器无效问题

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 有不少的动易用户升级了微软的IE8正式版,但在升级后都发现动易的后台编辑器无法使用了,症状就是点击任何功能图标都没有弹出设置窗口. 微软的IE8正式版已于2009年3月20日正式发布了,也有不少的动易用户升级了自己的浏览器,但在升级后都发现动易的后台编辑器无法使用了,症状就是点击任何功能图标都没有弹出设置窗口,经过搜索了一下,终于找到了解决I

动效设计如何从四个维度吸引你的注意力?

  动效设计正当红火,不过有很多同学担心驾驭不了它,容易被它喧宾夺主,今天百度的同学就从注意力这个角度给同学们聊聊,动效能从哪四个维度来吸引用户注意力,针对这几个维度,设计师该如何运用好动效设计,好文一篇,点赞别忘了艾特小伙伴. 近年来,随着ios和android系统对于动效设计的带动效应,多数产品对于动效设计也越来越重视,从app引导页到动作反馈,从官网介绍到hover效果,动效设计似乎已经成为一个成功产品的标配.但是动效也不是越绚丽越好,过于绚丽的动效对于我们的设计目标来说也许会适得其反,用

将ANGULAR与后端请求结合

简单的结合,却是很多应用的基础.RESTFUL就此而生.瘦服务,富客户.   <!DOCTYPE html> <html lang="en" ng-app="app"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <ti

PS把照片转成日式卡通动漫/芭比娃娃效果教程

效果图 原图 好吧,,,开始更新教程 之前看过我所谓教程的,,都知道我教程的渣程度... 经典的就是教程三部曲,, 第一步,新建文档, 第二步,沉思,,,,,, 第三步,把想象中的稿子画出来.. 好吧,表在意那些坑爹教程了.其实并非我不想分享自己的作画经验,只是实在对码字无力...所以这次我认认真真的写 好吧,废话不多说,,开始教程.... 这次是把人物转动漫,所以还是有参照物的.相对于默写人物,还是简单一点的.不过我还是推荐有意向玩绘画的朋友,除了必要的写生和临摹以外.也多做默写训练. 这样凭