Dojo 动画<13>

在这个教程中,你将学习到如何使用 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",function(baseFx,dom) {
    baseFx.animateProperty({
        node: dom.byId("anim8target"),properties: { borderWidth: 100 }
    }).play();
});

注意我们使用了Javascript的骆峰法来命名 borderWidth属性。 而不是css中的border-width属性。 我们依然传入node属性。 但这时,我们使用了一个新的"properties“键来指定我们想要变化的属性。


所有的属性的值可以是数字,也可是我们指定的任意多个。 在这个例子中,我们通过动画在同一时间改变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 属性。 毫秒数是整个动画持续的时间。

动画缓动

如果我们将动画时产生的值绘制出来,我们将看到随着时间发展从开始值到结束值的曲线图(横坐标为时间,纵坐标为值)。 绘制的曲线被称为“缓动曲线”。 最简单的缓动曲线是一条直线 - 比如一个节点以相等的速度从x:0 移动到 y:100. 但是运动看起来要自然一点应该是开始时很慢,在加速,慢到终点时在减速。 大部分运动都是以这种方式进行,但Dojo提供了更广泛的缓动函数以获得更好的效果和感受。 dojo/fx/easing模块有许多缓动曲线给我们使用:

require(["dojo/_base/fx","dojo/fx/easing","dojo/window","dojo/on",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,function(evt){
        baseFx.animateProperty({
            node: anim8target,properties: { top: 0 }
        }).play();
    });
});

在这个例子中,我们计算了窗口的高度,所以我们将 box层放置在窗口的底部(窗口的高度减去box层的高度)。通过使用bounceOut 缓动函数, 整个动画在终点值会像一个球一样弹跳。 也需要注意,top 属性的值是一个对像,这个对像包含start和end属性。 这让我们可以指定每个style 属性的运动范围。


!* 大部分缓动名称在末尾加上"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,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/dom-style","dojo/aspect",fx,domStyle,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,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,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时, 节点会被反转。


总结

Dojo 动画工具为你提供了方便和简单的创建动画。 动画可以从简单的几部分开始, 并且提供了非常有用的事件周期来同步必变。 在真实的世界中, 没有动画是从一个状态到另一个状态。 所以控制运动和视觉的变化是创建良好的用户体验的基础。

在之后的教程中,我们将看到在整个Dojo工具中都是相同的模式: 将简单的事情变简单, 复杂的事件变成可能。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


我有一个网格,可以根据更大的树结构编辑小块数据.为了更容易知道用户保存了什么,我希望当用户第一次看到网格时,网格处于不可编辑状态.当用户准备好后,他们可以单击编辑按钮,这将使网格的某些部分可编辑.然后,有一个保存或取消按钮可以保存更改或还原.在大多数情况下它是有效的.但
我即将开始开发一款教育性的视频游戏.我已经决定以一种我可以轻松打包为Web,Mobiles和可能的Standalone版本的方式来实现这一目标.我不想使用Flash.因此,我确信(无论如何我会听取建议)使用JavaScript和SVG.我正在对这个问题进行大量研究,但我很难把各个部分放在一起.我知道Raphae
我正在使用带有Grails2.3.9的Dojo1.9.DojoNumberTextBox小部件–我在表单中使用–将固定格式(JavaScript基本格式)的实数值(例如:12.56)设置为HTML表单输入字段(但根据浏览器区域设置显示/编辑它们,所以用户总是看到格式正确的数字).另一方面,Grails期望输入字段根据浏览器
1.引言鉴于个人需求的转变,本系列将记录自学arcgisapiforjavaScript的学习历程,本篇将从最开始的arcgisapiforjavaScript部署开始,个人声明:博文不在传道受业解惑,旨在方便日后复习查阅。由于是自学,文章中可能会出现一些纰漏,请留言指出,不必留有情面哦!2.下载ArcGISforDe
我正在阅读使用dojo’sdeclare进行类创建的语法.描述令人困惑:Thedeclarefunctionisdefinedinthedojo/_base/declaremodule.declareacceptsthreearguments:className,superClass,andproperties.ClassNameTheclassNameargumentrepresentsthenameofthec
我的团队由更多的java人员和JavaScript经验丰富组成.我知道这个问题曾多次被问到,但为了弄清楚我的事实,我需要澄清一些事情,因为我在客户端技术方面的经验非常有限.我们决定使用GWT而不是纯JavaScript框架构建我们的解决方案(假设有更多的Java经验).这些是支持我的决定的事实.>
路由dojo/framework/srcouting/README.mdcommitb682b06ace25eea86d190e56dd81042565b35ed1Dojo应用程序的路由路由FeaturesRoute配置路径参数RouterHistoryManagersHashHistoryStateHistoryMemoryHistoryOutletEventRouterContextInjectionOutl
请原谅我的无知,因为我对jquery并不熟悉.是否有dojo.connect()的等价物?我找到了这个解决方案:http:/hink-robot.com/2009/06/hitch-object-oriented-event-handlers-with-jquery/但是没有断开功能!你知道jquery的其他解决方案吗?有jquery.connect但这个插件在我的测试中不起作用.
与java类一样,在dojo里也可以定义constructor 构造函数,在创建一个实例时可以对需要的属性进行初始化。//定义一个类mqsy_yjvar mqsy_yj=declare(null,{     //thedefaultusername    username: "yanjun",          //theconstructor   
我一直在寻找一些最佳实践,并想知道Dojo是否具有框架特定的最佳实践,还是最好只使用通用的Javascript标准?特别是我主要是寻找一些功能和类评论的指导方针?解决方法:对于初学者来说,这是项目的风格指南:DojoStyleGuide
我有’05/17/2010’的价值我想通过使用dojo.date.locale将其作为“2010年5月17日”.我尝试过使用dojo.date.locale.parse,如下所示:x='05/17/2010'varx=dojo.date.locale.parse(x,{datePattern:"MM/dd/yyyy",selector:"date"});alert(x)这并没有给我所需的日期
我正在尝试创建一个包含函数的dojo类,这些函数又调用此类中的其他函数,如下所示:dojo.provide("my.drawing");dojo.declare("my.drawing",null,{constructor:function(/*Object*/args){dojo.safeMixin(this,args);this.container=args[0];
我知道你可以使用jQuery.noConflict为jQuery做这件事.有没有办法与Dojo做类似的事情?解决方法:我相信你可以.有关在页面上运行多个版本的Dojo,请参阅thispage.它很繁琐,但似乎是你正在寻找的东西.一般来说,Dojo和jQuery都非常小心,不会破坏彼此或其他任何人的变量名.
我有一个EnhancedGrid,用户经常使用复杂的过滤器.有没有办法允许用户保存或标记过滤器,以便将来可以轻松地重新应用它?我知道我可以通过编程方式设置过滤器,但我无法预测用户想要的过滤器.谢谢!编辑:自己做了一些进展…使用grid.getFilter()返回过滤器的JSON表示,然后使用json.strin
我有这个代码:dojo.declare("City",null,{constructor:function(cityid,cityinfo){}});dojo.declare("TPolyline",GPolyline,{constructor:function(points,color){},initialize:function(map){});应该是什
我遇到的问题是我的所有javascript错误似乎来自dojo.xd.js或子模块.我正在使用chrome调试器和许多dijit功能,如dijit.declaration和dojo.parser.这有点烦人,因为它很难找到简单的错误或滑倒.我希望我可以添加一个选项,允许我的调试器在我的非dojo代码中显示选项会发生的位置.我是
我正在使用DojoToolkit数字/解析函数来处理格式化和使用ICU模式语法解析字符串.有没有人知道有可能采取任意ICU模式字符串并以某种方式使用Dojo(或其他)库将其分解为它的部分(例如,对于数字模式,它可以被分解为小数位数,数千个分组等…).我希望这样做,而不需要让我的代码密切了
我有两个看似相关的问题,访问在不同的地方定义的javascript函数.我遇到的第一个问题是调用我在firgbug或safari控制台中定义的函数.我定义了一个名为getRed的函数,如下所示:functiongetRed(row,col){//dosomethingstuffandreturntheredvalueasa
我想添加一个在Ajax调用中指定的外部样式表.我已经找到了一种方法来使用jQuery(参见下面的示例),但是我需要使该方法适应dojoJavaScript框架.JQuery示例$('head').append('<linkrel="stylesheet"type="text/css"href="lightbox_stylesheet.css">');谢谢.解决方法:一旦你
我正在尝试使用dojo.connect将onMouseDown事件连接到图像,如:dojo.connect(dojo.byId("workpic"),"onMouseDown",workpicDown);functionworkpicDown(){alert("mousedown");}类似的代码几行后,我将onMouse*事件连接到dojo.body确实完全正常工作.但是当我点击图像时