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

时间:2018-12-11 23:03:07

标签: javascript

我需要动画制作2个divs女巫:

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

第一格的宽度应变为70%,第二格的宽度应变为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>

1 个答案:

答案 0 :(得分:4)

问题在于两个Anim调用都具有相同的params对象。两个params对象具有相同的确切回调drawFunc

为什么?,因为您在makeParams中正在这样做:

let params = def;

然后,您将其分配给params,这将依次更改原始的defaultParams(在此别名为def)。当第二个函数调用Anim时,第二个调用的回调drawFunc被分配给defaultParams对象。由于所有params对象基本上都是对defaultParams的引用,因此它们也被更改,并且对Anim的最后一次调用的回调也分配给了所有对象。

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

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>

相关问题: How do I correctly clone a JavaScript object?