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.