在这个教程中,我们将讲解Dojo 中的特效使用, 它将使你的网页或应用更加有趣。
开始
到目前为止,我们已经很容易操作DOM 以及处理DOM节点的事件。 可是, 我们在做这些动作时(删除,添加节点等), 过渡时会很生硬: 删除一个节点使它从一个页面中消失, 突然的消失会让浏览者感到迷惑。 使用 DOjo提供的标准特效, 我们可以流畅的用户体验。 更进一步, 如果我们在采用dojo/_base/fx 和dojo/fx模块, 我们链接和混全这些效果,创造更加眼花缭乱,动态的用户体验。
!* Dojo 1.9 有两个 fx 模块: dojo/_base/fx 和dojo/fx
- dojo/_base/fx 提供基本的特效方法,它也是之前Dojo基础里一部分。 包括, animateProperty,anim,fadeIn 和 fadeOut.
- dojo/fx 提供更高级的特效,包括: chain,combine,wipeIn wipeOut 和 slideTo
渐入/渐出
有一个动画你可能已经在应用程序里见过,那就是使一个节点渐入或者渐出。 这个效果非常普通也很简单, 它是 dojo/_base/fx核心效果的一部分。 我们可以使用它来在网页中隐藏和显示一个元素,感觉起来会更流畅。下面是一个例子:
<button id="fadeOutButton">Fade block out</button> <button id="fadeInButton">Fade block in</button> <div id="fadeTarget" class="red-block"> A red block </div> <script> require(["dojo/_base/fx","dojo/on","dojo/dom","dojo/domReady!"],function(fx,on,dom) { var fadeOutButton = dom.byId("fadeOutButton"),fadeInButton = dom.byId("fadeInButton"),fadeTarget = dom.byId("fadeTarget"); on(fadeOutButton,"click",function(evt){ fx.fadeOut({ node: fadeTarget }).play(); }); on(fadeInButton,function(evt){ fx.fadeIn({ node: fadeTarget }).play(); }); }); </script>
动画函数返回一个 dojo/_base/fx::Animation 对象,它提供了多种方法: play,pause,stop,status 和 gotoPrecent. 动画在它们创建是还没有开始播放, 必须手动的通过play方法开始。 如上所示。
擦除效果
<button id="wipeOutButton">Wipe block out</button> <button id="wipeInButton">Wipe block in</button> <div id="wipeTarget" class="red-block wipe"> A red block </div> <script> require(["dojo/fx",dom) { var wipeOutButton = dom.byId("wipeOutButton"),wipeInButton = dom.byId("wipeInButton"),wipeTarget = dom.byId("wipeTarget"); on(wipeOutButton,function(evt){ fx.wipeOut({ node: wipeTarget }).play(); }); on(wipeInButton,function(evt){ fx.wipeIn({ node: wipeTarget }).play(); }); }); </script>
擦除效果在 dojo/fx模块。 在这个例子中,我们给目标节点添加了一个 wipe 的css类。 因为wipe 的函数操作的是节点的内容高度,而不是一个确切的高度值。 "wipe"类设置目标节点的高度为"auto".
滑动效果
目前为此我们讲解了隐藏节点, 但如果我们想移动它们到某点该做什么呢? 渐入和渐隐或者擦除 都不能改变节点的位置。
<button id="slideAwayButton">Slide block away</button> <button id="slideBackButton">Slide block back</button> <div id="slideTarget" class="red-block slide"> A red block </div> <script> require(["dojo/fx",dom) { var slideAwayButton = dom.byId("slideAwayButton"),slideBackButton = dom.byId("slideBackButton"),slideTarget = dom.byId("slideTarget"); on(slideAwayButton,function(evt){ fx.slideTo({ node: slideTarget,left: "200",top: "200" }).play(); }); on(slideBackButton,left: "0",top: "100" }).play(); }); }); </script>
查看 Demo
动画事件
如之前讨论的, 所有的动画方法会返回一个 dojo/_base/fx::Animation 对象。 这些对象不仅仅提供 play或者pause来控制动画。 也提供一系列可被我们监听的事件, 事件为我们提供了在动画开始, 执续,完成之后,可以做些其它的动作。 两个非常重要也很常用的事件监听是 beforeBegin 和 onEnd
<button id="slideAwayButton">Slide block away</button> <button id="slideBackButton">Slide block back</button> <div id="slideTarget" class="red-block slide"> A red block </div> <script> require(["dojo/fx","dojo/dom-style",style,dom) { var slideAwayButton = dom.byId("slideAwayButton"),slideTarget = dom.byId("slideTarget"); on(slideAwayButton,function(evt){ // Note that we're specifying the beforeBegin as a property of the animation // rather than using connect. This ensures that our beforeBegin handler // executes before any others. var anim = fx.slideTo({ node: slideTarget,top: "200",beforeBegin: function(){ console.warn("slide target is: ",slideTarget); style.set(slideTarget,{ left: "0px",top: "100px" }); } }); // We could have also specified onEnd above alongside beforeBegin,// but it's just as easy to connect like so on(anim,"End",function(){ style.set(slideTarget,{ backgroundColor: "blue" }); },true); // Don't forget to actually start the animation! anim.play(); }); on(slideBackButton,function(evt){ var anim = fx.slideTo({ node: slideTarget,top: "100",beforeBegin: function(){ style.set(slideTarget,{ left: "200px",top: "200px" }); } }); on(anim,{ backgroundColor: "red" }); },true); anim.play(); }); }); </script>
你可能已经注意到 beforeBegin作为一个属性传递给参数对象。 原因在于确保动画在创建时连接上 beforeBegin。 因此,如果你在创建完动画之后在 注册 beforeBegin事件, 你的事件处理器会在动画的beforeBegin处理器之后处理(不能用on(anim,"beforeBegin",function(){}),没有暴露beforeBegin,只爆露出 "Begin",但 "Begin"是动画开始时,而不是开始前。 将监听器作为对象的属性, 你可以保证你的监听器最先执行。
动作链(连续的动画)
如果我们想依次触发动画该做什么? 我们可以在End事件的处理函数里设置下一步效果, 但这样不是很方便。 dojo/fx模块给我们提供了更方便的一些方法来设置动画依次执行或并列执行。而每个方法返回一个新的dojo/_base/fx::Animation对象, 每个对象都自己拥有一套代表整套(多个事件)的事件和方法。 让我们先看看 fx.chain 来依次播放多个动画。
<button id="slideAwayButton">Slide block away</button> <button id="slideBackButton">Slide block back</button> <div id="slideTarget" class="red-block slide chain"> A red block </div> <script> require(["dojo/_base/fx","dojo/fx",function(baseFx,fx,slideTarget = dom.byId("slideTarget"); // Set up a couple of click handlers to run our chained animations on(slideAwayButton,function(evt){ fx.chain([ baseFx.fadeIn({ node: slideTarget }),fx.slideTo({ node: slideTarget,top: "200" }),baseFx.fadeOut({ node: slideTarget }) ]).play(); }); on(slideBackButton,top: "100" }),baseFx.fadeOut({ node: slideTarget }) ]).play(); }); }); </script>
如你看到的, 我们创建了直接在fx.chain里创建了一些效果, 当返回了dojo/_base/fx::Animation 时立即调用 play方法开始整个动画。 我们不能在动画链里开始单独的动画,但利用fx.chain的事件处理器可以。
组合动画
dojo/fx提供的第二个方法是combine. combine将使多个动画在同一时间运行。 dojo/_base/fx::Animation 会在最长的动画执行完后返回 onEnd事件。 让我们看看这个例子:
<button id="slideAwayButton">Slide block away</button> <button id="slideBackButton">Slide block back</button> <div id="slideTarget" class="red-block slide chain"> A red block </div> <script> require(["dojo/_base/fx",slideTarget = dom.byId("slideTarget"); // Set up a couple of click handlers to run our combined animations on(slideAwayButton,function(evt){ fx.combine([ baseFx.fadeIn({ node: slideTarget }),top: "200" }) ]).play(); }); on(slideBackButton,function(evt){ fx.combine([ fx.slideTo({ node: slideTarget,baseFx.fadeOut({ node: slideTarget }) ]).play(); }); }); </script>
假若这样, fade 和 slideTo不在是依次运行,还是同时运行。
使用fx.chian 和 fx.combine,你可以建立一些非常复杂的动画序列。 也因为 chain 和 combine 都会返回一个 animation对象, 这样chain 和 combine方法返回的结果又可以被链接或组合。 允许你从简单的动画,在到复杂的动画。
总结
使用Dojo,非常简单的就能给你的网页添加效果。 通过dojo/_base/fx和 dojo/fx模块,你可以对DOM节点渐入和渐出, 也可以简单的移动和擦除你的节点。 通过 链接和组合动画可以创建更加高级的动画。
可是, 如果你想做更多高级的事件时, 比如调整一个DOM节的高度,而未必将高度一直委缩到 0. 或许还会通过动画来调整一个背景颜色. 还有更多的动画属性,查看
fx.animationProperty,更详细的内容会在下一教程中讲解。