同一个函数用不同的参数调用了两次,但只执行了最后一次



我有两个需要制作动画的div开关:

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

第一个div的宽度应该变为70%,第二个div的宽应该变为30%。但当我尝试为一个又一个div设置动画时,首先调用70%的函数,然后调用30%的函数,它们的宽度都变为30%。

Javascript代码:

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) + '%';
}
});

我不明白为什么会发生这种情况,也不明白如何使这两个功能正确工作。

代码片段(如果需要(:

(() => {
"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>

问题是两个Anim调用都有相同的params对象。两个params对象具有完全相同的回调drawFunc

为什么因为在makeParams中,您正在执行以下操作:

let params = def;

然后指定给params,这反过来又会更改原始defaultParams(此处别名为def(。当第二个函数调用Anim时,该第二个调用的回调drawFunc被分配给defaultParams对象。由于所有params对象基本上都是对defaultParams的引用,因此它们也会被更改,并且对Anim的最后一次调用的回调被分配给所有对象。

要解决此问题,只需使用Object.assign:克隆def

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

旁注:target属性在params对象中也发生了更改,但在更改之前,它被分配给init:中的一个新变量

const element = params.target || null;

因此,即使它在params对象中发生了变化,您也不会真正注意到,因为所有后续代码都使用变量element而不是params.target

工作代码:

(() => {
"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>

相关问题:如何正确克隆JavaScript对象?

相关内容

最新更新