我有两个需要制作动画的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对象?