Trying to implement simple easing in javascript (without jQuery) but unfortunately there doesn't seem to be any animation when the button is clicked (see below).

My goal is to get the hidden list item (the last item) visible by tweening the first item's margin left property. I know it isn't a CSS issue because manually modifying the style moves the list, but I'm not sure what the issue is. My guess is with how I'm calling the ease function but changing the params still wasn't working for me.

The easing part is below, entire code is here: 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);
}
有帮助吗?

解决方案

Your orig_value is NaN as parseFloat(el.style.marginLeft) returns nothing, even if you set an initial value in the css. i.e: margin-left: 15px; still will return nothing.

You can use window.getComputedStyle(...).getPropertyValue, similar to this:

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

This will give you the actual current value along with the px, i.e: 0px.
(It always return the value in px even if set in CSS as em or pt)

So you need to remove the px and the get the float value.

You can wrap this into a little helper similar to this:

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

    return parseFloat(valueOnly);
}

Another issue is that the moving of the actual element occurs within setTimeout executed inside a loop. The loop which calls setTimeout, causes each setTimeout to be queued nearly simultaneously, hence they all execute close to the same time, causing the element to just jump.

You can use a recursive sub-method inside your method which uses setTimeout to call itself until it is done. That way each setTimeout is triggered only after the specified interval, causing them to be executed close enough apart to the specified interval, similar to this:

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();
};

By having the setTimeout function call itself, it releases the resources, ensuring the drawing of the element can occur between each "iteration".

I updated your code to use this approach and it seems to work now.


DEMO - animating movement using computed style


You can most likely do this many other ways and also prettify this code for sure but but this should get you started either way.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top