JavaScript平滑动画从X,Y到X1,Y1

6
我希望能够平稳地将图像(或元素)从其实际的X、Y位置移动到X1、Y1。
当X和X1之间的距离等于Y和Y1之间的距离时,这很容易。但如果X的差距为100px,而Y的差距为273px呢?
作为一个新手,我不想重复造轮子!此外,由于我正在学习,我不想使用jQuery或类似的工具。我想要纯javascript。
请提供简单的脚本:-)

我假设该元素是绝对定位的... - Šime Vidas
1
定义不纯的 JavaScript :) - Šime Vidas
@Šime 我的意思是:不存在不纯的JavaScript。 - scessor
@epascarello,Didier不想使用jQuery并没有问题。但是如果有人说他不想重复造轮子,他需要一个库。jQuery和其他库正是这样的。 - scessor
3
有时候,当只需要完成一个简单的任务时,加载一个相对较大的库就是不必要的。 - duri
4个回答

7
一种解决方案:
function translate( elem, x, y ) {
    var left = parseInt( css( elem, 'left' ), 10 ),
        top = parseInt( css( elem, 'top' ), 10 ),
        dx = left - x,
        dy = top - y,
        i = 1,
        count = 20,
        delay = 20;

    function loop() {
        if ( i >= count ) { return; }
        i += 1;
        elem.style.left = ( left - ( dx * i / count ) ).toFixed( 0 ) + 'px';
        elem.style.top = ( top - ( dy * i / count ) ).toFixed( 0 ) + 'px';
        setTimeout( loop, delay );
    }

    loop();
}

function css( element, property ) {
    return window.getComputedStyle( element, null ).getPropertyValue( property );
}
实时演示:http://jsfiddle.net/qEVVT/1/

没错!:-) 感谢分享,这正是我在寻找的。 - Didier Levy
这对我也起作用,除了老旧的Internet Explorer。是的,我的div被绝对定位了。我测试了各种div元素的脚本/方法,但在IE中,没有任何移动。 - huzzm
这是为什么:在Internet Explorer中,window.getComputedStyle(element,null).getPropertyValue(property)只返回“auto”,而在所有其他浏览器中,它是以“px”结尾的数字。但我不知道如何解决这个问题。 - huzzm
好的,我通过在我的div元素中添加left: 0px;来解决了我的问题。 - huzzm

4
在具备不同能力的系统(CPU、图形处理能力以及其他运行在计算机上的任务)上实现流畅的动画并非易事。一个合适的实现方式需要开发一种有效的“tweening”算法,它可以自适应地(在动画运行时)计算出在动画中使用的增量,以保证动画按计划进行并尽可能平滑。
最好的方法是借鉴他人的经验和使用之前已经发明的技术。在今天这个时代,我永远不会试图自己从零开始编写它。CSS3的过渡/动画可以使用,但并不是所有浏览器都支持。jQuery和YUI3也提供了相应的实现或分析工具。我的首选是使用一个具有丰富功能集的框架来实现。如果您愿意,您甚至可以仅使用框架来做动画而不涉及其他方面。 YUI3甚至可以让您构建一个包含所需功能的最小代码库。jQuery本身也非常小。
如果您仍然坚决反对使用其中任何一个库,则可以下载每个库的相关模块源代码并研究其实现方式。在每个库中构建一个示例应用程序,并在感兴趣的位置设置断点,逐步跟踪其工作方式。这将是最好的老师,并向您展示如何构建一种有效的tweening算法,以适应主机计算机的速度能力。
为了让您了解一个基本的线性缓动的tweening算法是如何工作的,您首先需要计算出在您想要动画运行的时间内所需的动画步数。这可能只是关于系统支持的猜测。然后,将创建的步数除以动画运行的时间,并设置一个定时器,以便在那段时间到达时运行下一步。然后运行一两个动画步骤,查看实际经过的时间。如果计算机无法跟上您的步骤值,则您将落后于计划并必须自适应选择更大的步骤值。
现在,如果您想使用其他类型的缓动算法,显然需要更多的参与。
Firefox和Chrome还实现了一些新的实验API来帮助平滑动画。当我查看jQuery源代码时,发现它会在可用时使用它们。在Chrome中,它被称为webkitRequestAnimationFrame,您可以在Firefox博客文章这里阅读有关它的信息。

2
如果你的目标是现代浏览器,CSS过渡效果可以让生活更加轻松(例如火狐浏览器,在其他浏览器中,需要更改-moz前缀):
<body>
    <input type="button" onclick="move()" value="press" />
    <div id="sq" style="position:absolute; top:50px; left:50px; height:50px; width:50px; background-color:Black; -moz-transition : all 0.8s ease 0s;" />
</body>

而这个脚本

 function move() {
            var sq = document.getElementById("sq");
            sq.style.left = "300px";
            sq.style.top = "150px";
        }

0
如果我要从头开始编写它,我会从类似这样的东西开始:
function linearEase(start, end, percent) {
    return start + ((end - start) * percent);
}

function animateTo(settings) {
    var elem = settings.element;
    var ease = settings.ease;

    var start = { left: elem.offsetLeft, top: elem.offsetTop };

    var lastTime = new Date().getTime();
    var timeLeft = settings.totalTime;

    function update() {
        var currentTime = new Date().getTime();
        var elapsed = currentTime - lastTime;
        timeLeft -= elapsed;
        lastTime = currentTime;

        var percentDone = 1 - timeLeft/settings.totalTime;

        elem.style.top = ease(start.top, settings.top, percentDone) + "px" ;
        elem.style.left = ease(start.left, settings.left, percentDone) + "px" ;

        if(timeLeft > 0) {
            setTimeout(update, 33);
        }   
    }

    update();
}

例如,要在接下来的两秒钟内将一个 div 移动到 (50,50)。
var elem = document.getElementById("animatable");

setTimeout(function() {
    animateTo({
        element: elem, 
        left: 50, 
        top: 50, 
        totalTime: 2000,
        ease: linearEase
    })
}, 10);

这是一种相当标准的模式来完成这种操作。获取元素位置并设置样式可能可以更好地实现。但是,抽象出一个ease函数将使您在长期内的生活变得更加轻松。我提供了一个简单的线性缓动,但其他更复杂的缓动算法也将遵守相同的接口。

另一个需要注意的事情是,超时和间隔不能保证在固定时间运行,因此通常最好设置您希望过渡花费的总时间,然后计算自上次呈现以来经过了多少时间。

此外,如果您正在同时动画化一堆元素,我肯定会将其重构为单个“渲染循环”。对animateTo的调用将把工作程序推入工作程序队列中,但只有setTimeout循环计算经过的时间,然后调用每个工作程序,因此您不必担心无数个timeout闭包浮动。

无论如何,fiddle here


只是一个警告。ease在Safari中不受支持。 - user2831723

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接