在这一节中,你将学习如何运用dojo创建和合并特效为页面上的元素定制特效。
网络的用户界面,像其他的图形化用户界面一样,需要确保印象,所有的像素和按钮是连接到我们可以操纵的真实对象上。我们的大脑可以被数码产品所迷惑。随着幻想的存在而有虚拟的体验。当变化的过度是突兀的时候幻想将被识破。动画的过度让用户界面感觉着更加的自然很直觉,可以用来巧妙或不那么巧妙的改变页面上的关注点。
在这一节我们将学习dojo 提供的更多的动画。
让你修改,建立定制动画,以符合您的特定的用户界面的要求。
效果翻转
我们在前面已经讨论过dojo 内置的常用的特效。我们可以淡入淡出元素使用
baseFx.fadeIn
和
baseFx.fadeOut
(都在
dojo/_base/fx
模块中)我们使用
fx.slideTo
和
fx.wipeIn
在
dojo/fx
模块中。我们已经知道如何的向这些方法传递参数对象。一个节点属性,表明我们要实施动画的地方。
但是元素有无数的属性伴随着成组的值以用来设置动画。
假设我们要闪现背景或者在屏幕上移动节点。
为此我们需要
dojo
的通用动画工具。
baseFx.animateProperty
。
动画属性
如果你看了
fx.wipeIn
的源代码的话,你将看到基本的样式:高度属性被从
0
增加到他到自动或者自然高度,来看我们如何为任意的属性设置动画。
我们将设置节点
border
的动画。
<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
方法使用我们以前使用的模式
他设定了我们想要加动画的
border
的宽度属性,我们这样调用
animateProperty
方法
require(["dojo/_base/fx", "dojo/dom", "domReady!"], function(baseFx, dom) { baseFx.animateProperty({ node: dom.byId("anim8target"), properties: { borderWidth: 100 } }).play(); });
注意:我们使用JavaScript的小谢的驼峰属性名字:
borderWidth
。
而不是带有链接好的
border-width
属性名。我们也传入了一个节点属性。但是这次我们使用一个新的
'properties
'键来指明我们要使用动画的对象。同样的原则适用于所有的元素。我们可以有数字值。我们想设置多少就设置多少。
在下面的例子中我们将同时设置距上距右和头透明度。
逐渐消退的退出道左边。通过为每一个提供标准的
start
和
end
属性,我们可以创建具体的可重复的动画。
<h3>Demo: animateProperty with multiple style properties</h3> <button id="dropButton">Drop out block</button> <button id="ariseSirButton">Return block</button> <div id="anim8target" class="box" style="top: 100px; left: 300px; background-color: #fc9;width: 200px;height: 200px"> <div class="innerBox" >A box</div> </div> require(["dojo/_base/fx", "dojo/on", "dojo/dom", "dojo/domReady!"], function(baseFx, on, dom) { 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){ baseFx.animateProperty({ node: anim8target, properties: { top: { start: 100, end: 150 }, left: 0, opacity: { start: 1, end: 0 } }, duration: 800 }).play(); }); on(ariseSirButton, "click", function(evt){ baseFx.animateProperty({ node: anim8target, properties: { top: 100, left: 300, opacity: 1 } }).play(); }); });
注意我们仍然提供一个duration
(持续属性),这是动画所要持续的所有的毫秒的值。借此我们可以看看具体发生了什么。
缓冲
如果我们能够描绘,动画生成的值,我们将会看到一个从开始值到结束值得曲线。
曲线所参照的值叫做"easing".最简单的曲线是一条直线。
例如,以平均的速度从x:0移动到y:100,但是运动看起来更加的自然,当他慢慢的启动、加快当快要结束时放缓。默认的行为在很多地方都能用。但是dojo提供一系列的缓冲函数来得到正确的效果和感觉dojo/fx/easing 模块有一些缓和的曲线我们能够加载。
<style type="text/css"> * { outline: none !important; } body { margin: 0; padding: 2em; font-family: Lucida Sans,Lucida Grande,Arial !important; font-size: 13px !important; background: white; color: #333; } button { -webkit-transition: background-color 0.2s linear; border-radius:4px; -moz-border-radius: 4px 4px 4px 4px; -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); background-color: #E4F2FF; background-image: url("http://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dijit/themes/claro/form/images/button.png"); background-position: center top; background-repeat: repeat-x; border: 1px solid #769DC0; padding: 2px 8px 4px; font-size:1em; } button:hover { background-color: #AFD9FF; color: #000000; } h1 { font-size:1.5em; } /* Any demo specific styling needed for this tutorial only */ .box { position: absolute; height: 200px; width: 200px; background-color: #ddd; border: 1px #eee; padding: 5px; } .innerBox { margin: 5%; padding: 5px; background-color: white; } #container { position: relative; padding: 10px; height: 300px; width: 450px; } .contentBox { background-color: white; position: absolute; width: 200px; border: solid 1px #99c; margin: 5px; -moz-box-shadow: 10px 10px 5px #888; -webkit-box-shadow: 2px 3px 5px #888; box-shadow: 10px 10px 5px #888; } </style> <script src="http://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojo/dojo.js" data-dojo-config="isDebug: true, async: true"> </script> <script> 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(); }); }); </script> <h1>Demo: Animation Easing</h1> <button id="dropButton">Drop block</button> <button id="ariseSirButton">Return block</button> <div id="anim8target" class="box" style="top: 0; left: 50%; background-color: #fc9"> <div class="innerBox">A box</div> </div>
在这个例子中,我们计算视图窗口的高度。以便我们能够定位盒子到底部。通过使用easing 的bounceOut 函数,它到了最下面然后使它飘起来了一点点。在达到最终值之前。
同时要注意,最顶级的属性是一个拥有开始和结束属性的对象。他使我们更加的明白边界值我们想要添加动画对象的每个样式属性。
几乎所有的缓冲都有名字以 “In”或者”Out” 结束。或者两者都有。例如”InOut”.名字意味着。或者延迟是在开始之后或者是结束之前,或者在动画的两头。
放在一起
传统的动画应用一般使用一个时间轴去模型化在那个时期中发生了那些变化。他通常是在同一时间使事物发生变化。就像一个接一个一样。就像我没在一前的章节看到的特效一样。Dojo为每个提供了一个机制:fx.combine和fx.chain.
让我们看看怎么把多个工件放到一起。
对于此例子:开始时我们有两个写有内容的盒子。我们想让他们交换位置。为了加重改变,我们还会淡出在他们之后的背景色。
看以下代码:
<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,请求想要的模块。在我们传入以来的方法中初始化。
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.7.1/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 方法的实现如下:
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.7.1/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>
slideTo 方法用来移动每个节点。使用left 样式属性。我们还要使用animateProperty 来简化效果。两个分开的动画应该并行的执行,能够保证一次移动两个节点。fx.combine完成的是:将两个动画合成为一个。注意我们返回动画对象就像animateProperty和其他的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的数组包含两个独立的动画,我们想要连续的运行他们。先是节点交换然后改变背景色动画化容器初始化背景色是通过链接beforeBegin 事件完成的。在onEnd期间,我们有一些记录要做。当我们点击按钮时,节点倒过来了。
最终的代码是灵活、合理和易于扩展的。
你需要做背景动画并列运行交换吗?
怎样回复内容的透明度当他移动到右边的时候。经常发生的是。最难的一点是知道何时停止。
小结:
Dojo的动画工具在一般的情况下为你提供了便利和简单。对于特定的、定制的转换过程,你需要自己掌控。动画可以使用简单的小的部分建立,提供一组有用的事件生命周期来帮助同步的改变。
在真实世界中,没有什么是直接的从一个状态到另一个状态,所以掌控移动和视觉改变的能力是很重要的,以用来创建好的用户体验。
在以后章节,我们将通过相同行的模式介绍dojo Toolkit :使简单的事情容易,使难得事情变得有可能。