6

我想将图像(或元素)从其实际 X、Y 位置缓慢移动到 X1、Y1。

当X 和 X1 之间的距离等于Y 和 Y1 之间的距离时,它很容易。但是如果 X 差异是 100 像素而 Y 差异是 273 像素呢?

作为 Javascript 的新手,我不想重新发明轮子!此外,由于我正在学习,我不想使用 jQuery 或类似的东西。我想要纯javascript。

请提供简单的脚本:-)

4

4 回答 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/

于 2011-09-17T13:31:28.360 回答
4

在具有各种不同功能(CPU、图形处理能力、计算机上正在发生的其他事情)的系统上制作流畅的动画并非易事。正确的实现涉及开发一种有效的“补间”算法,该算法可以自适应地(随着动画运行)计算出动画中要使用的增量,以便保持进度并尽可能平滑。

做到这一点的最好方法是站在别人的肩膀上,使用以前发明的东西。在这个时代,我永远不会尝试自己从头开始写这个。它可以在 CSS3 过渡/动画中使用,但尚未在所有地方都支持。它可以在 jQuery 和 YUI3 中使用或分析。我的第一选择是使用其中一个具有丰富功能的框架。您不必将框架用于其他任何事情,如果需要,您可以将其用于动画。YUI3 甚至可以让你构建一个代码最少的库来满足你的需求。jQuery 一开始并不是很大。

如果您仍然反对使用其中一个库,请将源代码下载到每个库的相关模块并研究它们是如何做到的。在每个应用程序中构建一个示例应用程序,并逐步了解它的工作原理,在有趣的地方设置断点。那将是最好的老师,向您展示如何构建一个有效的补间算法,以适应主机的速度能力。

为了让您了解补间算法如何用于直线动画(使用线性缓动),您需要对动画运行时间的动画步长值进行初始计算。这可能只是对系统可以支持什么的猜测。您将创建的步骤数划分为动画运行的时间,并为该时间量设置一个计时器,以便您知道何时运行下一步。然后,您运行一两步动画,您会看到实际经过了多少时间。如果计算机跟不上您的步数,您将落后于计划,您将不得不适应并选择更大的步数。

现在,如果你想做一些除了线性缓动之外的事情,显然还有更多的事情要做。

Firefox 和 Chrome 还实现了一些新的实验性 API 来帮助实现流畅的动画效果。我在查看 jQuery 源代码时自己发现了这一点,因为它在可用时使用它。在 Chrome 中,它被称为 webkitRequestAnimationFrame,您可以在 Firefox 博客文章中了解它。

于 2011-09-17T14:46:13.713 回答
1

如果您的目标是现代浏览器,CSS 过渡让生活更轻松(例如,对于 firefox,对于其他浏览器,更改 -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";
        }
于 2011-09-17T13:37:52.053 回答
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闭包漂浮。

无论如何,在这里摆弄

于 2011-09-17T15:46:54.483 回答