在这个教程中,你将学习到如何使用 Dojo 给一个网页上的元素创建自定义的动画。 查看完整的Demo 开始 网页界面,像其它图形用户界面一样,需要保持一个幻想,幻想所有的像素和按纽
在这个教程中,你将学习到如何使用 Dojo 给一个网页上的元素创建自定义的动画。 查看完整的Demo
开始
网页界面,像其它图形用户界面一样,需要保持一个幻想,幻想所有的像素和按纽都是我们可以操作的真实事件。只要幻想存在,我们的大脑就停止怀疑并且进行有效的虚拟用户体验。当在变化时的过度显得很生硬的话会打断这种幻想。 动画转场可以帮助UI 感觉起来更自然和直观。在这个教程里,我们将学习更多Dojo的动画工具, 为你创建自定义的动画以适合你某些特定UI的需求。 (整段话太文艺,不像讲代码那样直接,水平有限不好翻译)
Dojo 特效
我们在上一个教程里已经讨论过内建和常用的特效, effects available in Dojo. 我们可以使用baseFx.fadeIn 和 baseFx.fadeOut (两者都在dojo/_base/fx模块)来淡入和淡出一个元素,之后我们讲了 dojo/fx模块中的 fx.slideTo 和 fx.wipeIn。 然后给这些函数传递一个参数对像。
require(["dojo/fx", "dojo/dom", "dojo/domReady!"], function(fx, dom) { fx.wipeIn({ node: dom.byId("wipeTarget") }).play(); });
但是我们可能改变元素的多个属性值, 假如 我们想闪动背景,或者在屏幕里移动节点? 为了满足这些需求, Dojo 一般使用到baseFx.animateProperty.
Animating Properties (动画属性)
如果你看过fx.wipeIn的源码,你会发现它主要是改变节点的高由0变为 auto或者自然高度。 看看我们如何创建任意属性的动画, 我们将通过动画来改变一个节点的边框。 以下是HTML标签:<button id="startButton">Grow Borders</button> <button id="reverseButton">Shrink Borders</button> <div id="anim8target" class="box" style="border-style:outset"> <div class="innerBox">A box</div> </div>
animateProperty 方法 跟我们已经用到的fx 或者 fadeIn方法的使用是一样的。 特别之处在于border-width属性。 所以我们调用animateProperty如下:
require(["dojo/_base/fx", "dojo/dom", "dojo/domReady!"], function(baseFx, dom) { baseFx.animateProperty({ node: dom.byId("anim8target"), properties: { borderWidth: 100 } }).play(); });
注意我们使用了Javascript的骆峰法来命名 borderWidth属性。 而不是css中的border-width属性。 我们依然传入node属性。 但这时,我们使用了一个新的"properties“键来指定我们想要变化的属性。
查看Demo
所有的属性的值可以是数字,也可是我们指定的任意多个。 在这个例子中,我们通过动画在同一时间改变top, left 和opacity的值。 使用得元素逐渐消失。 通过提供给每个属性提供指定的start和end, 我们创建更加明确,可重复的动画.
baseFx.animateProperty({ node: anim8target, properties: { top: { start: 25, end: 150 }, left: 0, opacity: { start: 1, end: 0 } }, duration: 800 }).play();注意, 我们也提供了duration 属性。 毫秒数是整个动画持续的时间。 查看Demo
动画缓动
如果我们将动画时产生的值绘制出来,我们将看到随着时间发展从开始值到结束值的曲线图(横坐标为时间,纵坐标为值)。 绘制的曲线被称为“缓动曲线”。 最简单的缓动曲线是一条直线 - 比如一个节点以相等的速度从x:0 移动到 y:100. 但是运动看起来要自然一点应该是开始时很慢,在加速,慢到终点时在减速。 大部分运动都是以这种方式进行,但Dojo提供了更广泛的缓动函数以获得更好的效果和感受。 dojo/fx/easing模块有许多缓动曲线给我们使用:require(["dojo/_base/fx", "dojo/dom", "dojo/fx/easing", "dojo/window", "dojo/on", "dojo/domReady!"], function(baseFx, dom, easing, win, on) { var dropButton = dom.byId("dropButton"), ariseSirButton = dom.byId("ariseSirButton"), anim8target = dom.byId("anim8target"); // Set up a couple of click handlers to run our animations on(dropButton, "click", function(evt){ // get the dimensions of our viewport var viewport = win.getBox(win.doc); baseFx.animateProperty({ // use the bounceOut easing routine to have the box accelerate // and then bounce back a little before stopping easing: easing.bounceOut, duration: 500, node: anim8target, properties: { // calculate the 'floor' // and subtract the height of the node to get the distance from top we need top: { start: 0, end:viewport.h - anim8target.offsetHeight } } }).play(); }); on(ariseSirButton, "click", function(evt){ baseFx.animateProperty({ node: anim8target, properties: { top: 0 } }).play(); }); });
在这个例子中,我们计算了窗口的高度,所以我们将 box层放置在窗口的底部(窗口的高度减去box层的高度)。通过使用bounceOut 缓动函数, 整个动画在终点值会像一个球一样弹跳。 也需要注意,top 属性的值是一个对像,这个对像包含start和end属性。 这让我们可以指定每个style 属性的运动范围。
查看 Demo
!* 大部分缓动名称在末尾加上"in ”或者 "out", 或者 ”inOut". 名字意味着缓动是在动画的开始(in)或者结尾(out), 或者两者(inOut)。 获得更多信息,请查看 the dojo/fx/easing Reference Guide .
综合Dojo 动画知识,完成实际案例
传统的动画软件一般会使用时间轴来模似在什么时期有什么变化, 正常的是有的事物是同时移动的,也有的是在其它之后移动的。 如我们之前讲解的 效果教程, Dojo 也提供了一个机制: fx.combine 和 fx.chain. 让我们看看如何综合使用它们。这个Demo, 我们先设置了两个想要交换的盒子。 为了突出在交换时的过程,会在淡出两个盒子的背景层。 以下是我们要用到的html标签:
<button id="swapButton">Swap</button> <div class="container" id="container"> <div id="content1" class="contentBox" style="top: 0; left: 0"> <div class="innerBox">1: Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident.</div> </div> <div id="content2" class="contentBox" style="top: 0; left: 250px"> <div class="innerBox">2: Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</div> </div> </div>
像往常一样,我们加载Dojo, 然后请求相关的模块, 然后初始化require内的函数。
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.2/dojo/dojo.js" data-dojo-config="isDebug: true, async: true"> <script> require(["dojo/_base/fx", "dojo/fx", "dojo/fx/easing", "dojo/dom-style", "dojo/dom", "dojo/on", "dojo/aspect", "dojo/domReady!"], function(baseFx, fx, easing, domStyle, dom, on, aspect) { function swapAnim(node1, node2) { // create & return animation which swaps the positions of 2 nodes } var originalOrder = true; // track which order our content nodes are in var swapButton = dom.byId("swapButton"), c1 = originalOrder ? dom.byId("content1") : dom.byId("content2"), c2 = originalOrder ? dom.byId("content2") : dom.byId("content1"), container = dom.byId("container"); // Set up a click handler to run our animations on(swapButton, "click", function(evt){ // pass the content nodes into swapAnim to create the node-swapping effect // and chain it with a background-color fade on the container // ensure the originalOrder bool gets togged properly for next time }); }); </script>
先从简单部分开始在构成复杂的动画非常有用, 在这里,我先将动画分离成几个独立的部分, 我们可以保持位置效换的代码的通用和重用性。 swapAnim函数实现如下:
function swapAnim(node1, node2) { var posn1 = parseInt(domStyle.get(node1, "left")), posn2 = parseInt(domStyle.get(node2, "left")); return moveNodes = fx.combine([ fx.slideTo({ duration: 1200, node: node2, left: posn1 }), fx.slideTo({ duration: 1200, node: node1, left: posn2 }) ]); }slideTo 里设置left样式属性,来实际移动每一个节点。 我们也可以使用animateProperty实现相似的效果。 两个盒子的动画并行执行。 注意 我们将返回一个动画对像, 正如animateProoperty 和其它Dojo方法做的一样, 当需要播放动画时,在调用这个方法的地方在调用play();
// Set up a click handlers to run our animations on(swapButton, "click", function(evt){ // chain the swap nodes animation // with another to fade out a background color in our container var anim = fx.chain([ swapAnim(c1, c2), baseFx.animateProperty({ node: container, properties: { backgroundColor: "#fff" } }), ]); // before the animation begins, set initial container background aspect.before(anim, "beforeBegin", function(){ domStyle.set(container, "backgroundColor", "#eee"); }); // when the animation ends, toggle the originalOrder on(anim, "End", function(n1, n2){ originalOrder = !originalOrder; }); anim.play(); });
这里是点击处理函数 , 如我们之前fx.combine, 两个单独动画的 数组会被 传递给 fx.chain。 可以我们要串联运行: 先运行 节点效换,然后在改变背景颜色。container的初始化背景化颜色连接到beforeBegin 事件前设置。 并且在结束时做一个标记,以确保我们点击next时, 节点会被反转。
查看Demo
总结
Dojo 动画工具为你提供了方便和简单的创建动画。 动画可以从简单的几部分开始, 并且提供了非常有用的事件周期来同步必变。 在真实的世界中, 没有动画是从一个状态到另一个状态。 所以控制运动和视觉的变化是创建良好的用户体验的基础。在之后的教程中,我们将看到在整个Dojo工具中都是相同的模式: 将简单的事情变简单, 复杂的事件变成可能。