【问题标题】:Javascript easing not animatingJavascript 缓动不动画
【发布时间】:2014-01-02 21:05:53
【问题描述】:

尝试在 javascript(没有 jQuery)中实现简单的缓动,但不幸的是,当单击按钮时似乎没有任何动画(见下文)。

我的目标是通过补间第一个项目的左边距属性来使隐藏的列表项目(最后一个项目)可见。我知道这不是 CSS 问题,因为手动修改样式会移动列表,但我不确定问题是什么。我的猜测是我如何调用 ease 函数,但更改参数仍然对我不起作用。

缓动部分如下,完整代码在这里:Fiddle

JS:

var start = document.getElementById('start'),
    list = document.getElementById('my-list'),
    imgs = list.getElementsByTagName('img'),
    last_img = imgs[imgs.length -1 ];

    ease = function(t, b, c, d) {
        if ((t/=d/2) < 1) return c/2*t*t + b;
            return -c/2 * ((--t)*(t-2) - 1) + b;
    },

    shift_imgs = function(el) {
        var orig_value = parseFloat( el.style.marginLeft ),
            end_value = -37,
            change = Math.abs( end_value - orig_value ),
            duration = 1, // 1 second
            time = 0;

        for ( var i = 0; i < change; i++ ) {
            setTimeout(function() {
                el.style.marginLeft = ( parseFloat( el.style.marginLeft ) + 1 ) + 'px';
                }, time);
            time = ease(time, orig_value, change, duration);
        }
    };

start.onclick = function() {
    shift_imgs(last_img);
}

【问题讨论】:

  • 为什么不直接使用 CSS 过渡? unlimited bezier functions 触手可及;)
  • @NiettheDarkAbsol 是的,我很了解 CSS3,但这更像是个人练习 :)
  • 很公平!我自己也经历过这个练习,所以我完全理解 :) 但主要问题是 margin-left:123 无效。有效的 CSS 是 margin-left:123px - 记得添加单位,即使在 JavaScript 中也是如此;)

标签: javascript html css easing


【解决方案1】:

您的orig_valueNaN,因为parseFloat(el.style.marginLeft) 不会返回任何内容,即使您在css 中设置了初始值。即:margin-left: 15px; 仍然不会返回任何内容。

你可以使用window.getComputedStyle(...).getPropertyValue,类似这样:

window.getComputedStyle(el, null).getPropertyValue("margin-left");

这将为您提供实际的当前值以及px,即:0px
(即使在 CSS 中设置为 empt)

所以你需要删除px 并获取浮点值。

你可以把它包装成一个类似这样的小助手:

getElementMarginLeftAsFloat = function (el) {
    var pxValue = window.getComputedStyle(el, null).getPropertyValue("margin-left");
    var valueOnly = pxValue.substring(0, pxValue.length - 2);

    return parseFloat(valueOnly);
}

另一个问题是实际元素的移动发生在循环内执行的setTimeout 内。调用setTimeout 的循环导致每个setTimeout 几乎同时排队,因此它们几乎同时执行,导致元素只是跳转。

您可以在方法中使用递归子方法,该方法使用setTimeout 调用自身,直到完成。这样每个setTimeout 仅在指定的时间间隔后才被触发,从而使它们在指定的时间间隔内足够接近地执行,类似于:

shift_imgs = function (el) {
    var orig_value = getElementMarginLeftAsFloat(el),
        end_value = -37,
        change = Math.abs(end_value - orig_value),
        duration = 1, // 1 second
        time = 0;

    function doShift() {
        currentValue = getElementMarginLeftAsFloat(el);

        if(currentValue+1 > change){
            return;
        };

        el.style.marginLeft = (currentValue + 1) + 'px';
        time = ease(time, orig_value, change, duration);
        setTimeout(doShift, time);
    }

    doShift();
};

通过让setTimeout 函数调用自身,它释放资源,确保元素的绘制可以在每次“迭代”之间进行。

我更新了你的代码以使用这种方法,现在它似乎可以工作了。


DEMO - 使用计算样式动画运动


您很可能可以通过许多其他方式执行此操作,也可以肯定地美化此代码,但这应该可以让您以任何一种方式开始。

【讨论】:

  • 很好地抓住了弗朗索瓦的错别字!我更新了代码和小提琴,但不幸的是我仍然没有看到动画。会不会是在 1 秒内移动 37px 太快以至于动画无法被注意到?
  • @smaili:是的,我现在看到它只是跳跃。我错过了预期,并假设您按像素点击。对于那个很抱歉。我现在更新了答案以确保动画实际发生。 for 循环不起作用。元素的绘制只是在循环完成后发生。我已经用递归子方法替换了循环,该子方法在setTimeout 中不断调用自身,这会导致绘制执行每个“迭代”。
  • 是的,解决了它。感谢弗朗索瓦的帮助和详细的回答!
  • @smaili:我现在还更新了关于为什么循环“似乎”不起作用的解释。循环中的setTimeout 确实可以正常工作,尽管在您的示例中,循环执行速度非常快,它几乎同时将所有setTimeouts 调用排队,中间只有一毫秒(可能是2),因此它们执行同时,导致元素“跳跃”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-31
  • 2016-03-22
  • 1970-01-01
  • 2011-11-19
  • 2016-06-28
相关资源
最近更新 更多