简体   繁体   中英

The same function called twice with different parameters but only last is executed

I have 2 divs witch I need to animate:

<div class="d"></div>
<div class="p"></div>

Width of first div should become 70% and width of second div should become 30%. But when I'am trying to animate one div after another, calling at first function for 70% and then function for 30%, width of both of them become 30%.

Javascript code:

Anim({
    target: document.getElementsByClassName('d')[0],
    drawFunc: (progress, element) => {
        element.style.width = (progress * 70) + '%';
    }
});

Anim({
    target: document.getElementsByClassName('p')[0],
    drawFunc: (progress, element) => {
        element.style.width = (progress * 30) + '%';
    }
});

I don't understand why this is happening and how to make both functions work correctly.

Code snippet if needed:

 (() => { "use strict"; const init = (params) => { const start = performance.now(); const element = params.target || null; requestAnimationFrame(function animate(time) { let timeFraction = (time - start) / params.duration; if (timeFraction > 1) { timeFraction = 1; } const progress = params.timingFunc(timeFraction, params.timingArg); params.drawFunc(progress, element); if (timeFraction < 1) { requestAnimationFrame(animate); } if (params.callback) { if (timeFraction >= 1) { params.callback(); } } }); }; const timingFunctions = { linear: (timeFraction) => { return timeFraction; } }; const paces = { easeIn: (func) => { return timingFunctions[func]; } }; const defaultParams = { duration: 1000, timingFunc: paces.easeIn('linear'), timingArg: null, delay: null, callback: null }; const makeParams = (def, add) => { let params = def; if (add) { for (let i in add) { if (Object.prototype.hasOwnProperty.call(add, i)) { params[i] = add[i]; } } } return params; }; function Anim(paramArgs) { const params = makeParams(defaultParams, paramArgs); if ('timingFunc' in paramArgs) { params.timingFunc = (typeof paramArgs.timingFunc === 'function') ? paramArgs.timingFunc : paces[paramArgs.timingFunc.pace](paramArgs.timingFunc.func); } if (!params.delay) { init(params); } else { setTimeout(() => { init(params); }, params.delay); } } window.Anim = Anim; })(); Anim({ target: document.getElementsByClassName('d')[0], drawFunc: (progress, element) => { element.style.width = (progress * 70) + '%'; } }); Anim({ target: document.getElementsByClassName('p')[0], drawFunc: (progress, element) => { element.style.width = (progress * 30) + '%'; } }); 
 .d, .p { background-color: red; height: 50px; width: 0; margin-top: 10px; } 
 <div class="d"></div> <div class="p"></div> 

The problem is that both Anim calls have the same params object. Both params objects have the same exact callback drawFunc .

Why? Because in makeParams you are doing this:

let params = def;

Then you assign to params which in turn alters the original defaultParams (aliased here as def ). When the second function calls Anim , the callback drawFunc of this second call gets assigned to the defaultParams object. Since all params objects are basically a reference to defaultParams , they get altered too, and the callback of the last call to Anim gets assigned to all of them.

To fix this, just clone def using Object.assign :

let params = Object.assign({}, def);

Side note: The target property is also altered in the params object, but before it changes, it gets assigned to a new variable inside init :

const element = params.target || null;

Thus, even though it changes in the params object, you don't really notice because all subsequent code uses the variable element instead of params.target .

Working code:

 (() => { "use strict"; const init = (params) => { const start = performance.now(); const element = params.target || null; requestAnimationFrame(function animate(time) { let timeFraction = (time - start) / params.duration; if (timeFraction > 1) { timeFraction = 1; } const progress = params.timingFunc(timeFraction, params.timingArg); params.drawFunc(progress, element); if (timeFraction < 1) { requestAnimationFrame(animate); } if (params.callback) { if (timeFraction >= 1) { params.callback(); } } }); }; const timingFunctions = { linear: (timeFraction) => { return timeFraction; } }; const paces = { easeIn: (func) => { return timingFunctions[func]; } }; const defaultParams = { duration: 1000, timingFunc: paces.easeIn('linear'), timingArg: null, delay: null, callback: null }; const makeParams = (def, add) => { let params = Object.assign({}, def); if (add) { for (let i in add) { if (Object.prototype.hasOwnProperty.call(add, i)) { params[i] = add[i]; } } } return params; }; function Anim(paramArgs) { const params = makeParams(defaultParams, paramArgs); if ('timingFunc' in paramArgs) { params.timingFunc = (typeof paramArgs.timingFunc === 'function') ? paramArgs.timingFunc : paces[paramArgs.timingFunc.pace](paramArgs.timingFunc.func); } if (!params.delay) { init(params); } else { setTimeout(() => { init(params); }, params.delay); } } window.Anim = Anim; })(); Anim({ target: document.getElementsByClassName('d')[0], drawFunc: (progress, element) => { element.style.width = (progress * 70) + '%'; } }); Anim({ target: document.getElementsByClassName('p')[0], drawFunc: (progress, element) => { element.style.width = (progress * 30) + '%'; } }); 
 .d, .p { background-color: red; height: 50px; width: 0; margin-top: 10px; } 
 <div class="d"></div> <div class="p"></div> 

Related issue: How do I correctly clone a JavaScript object?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM