Javascript 缓动而不是动画

标签 javascript html css easing

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

我的目标是通过补间第一项的 margin left 属性使隐藏的列表项(最后一项)可见。我知道这不是 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);
}

最佳答案

您的 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 返回值)

因此您需要删除 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 - 使用计算样式动画运动


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

关于Javascript 缓动而不是动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20881579/

相关文章:

javascript - 如何将记录解析为json数据

javascript - 使用ajax以mvc模式通过 Controller 发送数据

css - 为 li 使用背景图像

html - 为什么 <p> 在 float <ul> 之后从一个新行开始?

html - 截断表格单元格中的溢出文本,因此表格不会比屏幕宽

html - 为什么 Chrome DevTools 设备工具栏不能与不同的样式表一起正常工作?

html - 垂直菜单,鼠标悬停时子菜单会飞出

javascript - 纯粹使用 javascript 而不使用 Nodejs 下载 azure blob?

javascript - 外部 javascript 文件无法识别 jQuery

html - 使用 CSS 的图形和部分的多个计数器