如何实现具有唯一 setInterval 变量名称的 for-loop?

How to implement a for-loop with unique setInterval variable names?

我创建了一个 svg 百分比环,如下所示。

var dark = document.getElementById('dark');
var light = document.getElementById('light');
var svg = document.getElementById('svg');
var t = 5;
var percentage = parseInt(document.getElementById('perc').innerHTML.slice(0, -1), 10);
var theta = 0;
var maxTheta = (180 * percentage) / 50;
var radius = svg.getAttribute('width') / 2;
dark.setAttribute('transform', 'translate(' + radius + ',' + radius + ')');

var animate = setInterval(function() {
  theta += 0.5;
  var x = Math.sin(theta * Math.PI / 180) * radius;
  var y = Math.cos(theta * Math.PI / 180) * -radius;
  var d = 'M0,0 v' + -radius + 'A' + radius + ',' + radius + ' 1 ' + ((theta > 180) ? 1 : 0) + ',1 ' + x + ',' + y + 'z';
  dark.setAttribute('d', d);
  if (theta > maxTheta) {
    clearInterval(animate);
  }
}, t);
<svg id="svg" width="140" height="140" viewBox="-1 -1 141 141">
  <path id="light" d="M70,70 v-70 a70,70 0 0,1 0,140 a70,70 0 1,1 0,-140" fill="#DD1111" />
  <path id="dark" d="M70,70 v-70 a70,70 0 0,1 0,0" fill="#710000" />
  <path d="M20,70 a50,50 0 0,1 100,0 a50,50 0 0,1 -100,0" fill="white" />
  <text id="perc" x="70" y="79" font-size="30px" text-anchor="middle">44%</text>
</svg>


它工作正常,但是我很难实现多个环的动画部分。

比如我有三个戒指

我目前使用 setInterval() 处理动画的方式是:

var animOne = setInterval(function() {
  theta[0] += 0.5;
  var x = Math.sin(theta[0] * Math.PI / 180) * radius;
  var y = Math.cos(theta[0] * Math.PI / 180) * -radius;
  var d = 'M0,0 v' + -radius + 'A' + radius + ',' + radius + ' 1 ' + ((theta[0] > 180) ? 1 : 0) + ',1 ' + x + ',' + y + 'z';
  dark[0].setAttribute('d', d);
  if (theta[0] > maxTheta[0]) {
    clearInterval(animOne);
  }
}, t);

var animTwo = setInterval(function() {
  theta[1] += 0.5;
  var x = Math.sin(theta[1] * Math.PI / 180) * radius;
  var y = Math.cos(theta[1] * Math.PI / 180) * -radius;
  var d = 'M0,0 v' + -radius + 'A' + radius + ',' + radius + ' 1 ' + ((theta[1] > 180) ? 1 : 0) + ',1 ' + x + ',' + y + 'z';
  dark[1].setAttribute('d', d);
  if (theta[1] > maxTheta[1]) {
    clearInterval(animTwo);
  }
}, t);

var animThree = setInterval(function() {
  theta[2] += 0.5;
  var x = Math.sin(theta[2] * Math.PI / 180) * radius;
  var y = Math.cos(theta[2] * Math.PI / 180) * -radius;
  var d = 'M0,0 v' + -radius + 'A' + radius + ',' + radius + ' 1 ' + ((theta[2] > 180) ? 1 : 0) + ',1 ' + x + ',' + y + 'z';
  dark[2].setAttribute('d', d);
  if (theta[2] > maxTheta[2]) {
    clearInterval(animThree);
  }
}, t);

这当然不是应该的方式。

如何为这段代码创建一个 for 循环?

应该看起来像:

for (i = 0; i < dark.length; i++) {
  var ____ = setInterval(function() {
    theta[2] += 0.5;
    var x = Math.sin(theta[i] * Math.PI / 180) * radius;
    var y = Math.cos(theta[i] * Math.PI / 180) * -radius;
    var d = 'M0,0 v' + -radius + 'A' + radius + ',' + radius + ' 1 ' + ((theta[i] > 180) ? 1 : 0) + ',1 ' + x + ',' + y + 'z';
    dark[i].setAttribute('d', d);
    if (theta[i] > maxTheta[i]) {
      clearInterval(____);
    }
  }, t);
}

有没有可能做这样的事情?如果没有,还可以怎么做?


完整代码:

var dark = document.getElementsByClassName('dark');
var svg = document.getElementsByClassName('svg')[0];
var radius = svg.getBBox().width / 2;
var t = 0.5,
  x = 0,
  y = 0;
var theta = {
  0: 0,
  1: 0,
  2: 0
};
var anims = {};
var maxTheta = calcTheta(document.getElementsByClassName('perc'));
for (i = 0; i < dark.length; i++) {
  dark[i].setAttribute('transform', 'translate(' + radius + ',' + radius + ')');
}

function calcTheta(el) {
  var jbo = {};
  for (i = 0; i < el.length; i++) {
    jbo[i] = (180 * parseInt(el[i].innerHTML.slice(0, -1), 10)) / 50;
  }
  return jbo;
}
var animOne = setInterval(function() {
  theta[0] += 0.5;
  var x = Math.sin(theta[0] * Math.PI / 180) * radius;
  var y = Math.cos(theta[0] * Math.PI / 180) * -radius;
  var d = 'M0,0 v' + -radius + 'A' + radius + ',' + radius + ' 1 ' + ((theta[0] > 180) ? 1 : 0) + ',1 ' + x + ',' + y + 'z';
  dark[0].setAttribute('d', d);
  if (theta[0] > maxTheta[0]) {
    clearInterval(animOne);
  }
}, t);
var animTwo = setInterval(function() {
  theta[1] += 0.5;
  var x = Math.sin(theta[1] * Math.PI / 180) * radius;
  var y = Math.cos(theta[1] * Math.PI / 180) * -radius;
  var d = 'M0,0 v' + -radius + 'A' + radius + ',' + radius + ' 1 ' + ((theta[1] > 180) ? 1 : 0) + ',1 ' + x + ',' + y + 'z';
  dark[1].setAttribute('d', d);
  if (theta[1] > maxTheta[1]) {
    clearInterval(animTwo);
  }
}, t);
var animThree = setInterval(function() {
  theta[2] += 0.5;
  var x = Math.sin(theta[2] * Math.PI / 180) * radius;
  var y = Math.cos(theta[2] * Math.PI / 180) * -radius;
  var d = 'M0,0 v' + -radius + 'A' + radius + ',' + radius + ' 1 ' + ((theta[2] > 180) ? 1 : 0) + ',1 ' + x + ',' + y + 'z';
  dark[2].setAttribute('d', d);
  if (theta[2] > maxTheta[2]) {
    clearInterval(animThree);
  }
}, t);
#container {
  width: 100%;
}
svg {
  display: inline-block;
}
<div id="container">
  <svg class="svg" width="33%" height="33%" viewBox="0 0 141 141" shape-rendering="geometricPrecision">
    <path class="light" d="M70,70 v-70 a70,70 0 0,1 0,140 a70,70 0 1,1 0,-140" fill="#DD1111" />
    <path class="dark" d="M70,70 v-70 a70,70 0 0,1 0,0" fill="#710000" />
    <path d="M20,70 a50,50 0 0,1 100,0 a50,50 0 0,1 -100,0" fill="white" />
    <text class="perc" x="70" y="79" font-size="30px" text-anchor="middle">44%</text>
  </svg>
  <svg class="svg" width="33%" height="33%" viewBox="0 0 141 141" shape-rendering="geometricPrecision">
    <path class="light" d="M70,70 v-70 a70,70 0 0,1 0,140 a70,70 0 1,1 0,-140" fill="#DD1111" />
    <path class="dark" d="M70,70 v-70 a70,70 0 0,1 0,0" fill="#710000" />
    <path d="M20,70 a50,50 0 0,1 100,0 a50,50 0 0,1 -100,0" fill="white" />
    <text class="perc" x="70" y="79" font-size="30px" text-anchor="middle">20%</text>
  </svg>
  <svg class="svg" width="33%" height="33%" viewBox="0 0 141 141" shape-rendering="geometricPrecision">
    <path class="light" d="M70,70 v-70 a70,70 0 0,1 0,140 a70,70 0 1,1 0,-140" fill="#DD1111" />
    <path class="dark" d="M70,70 v-70 a70,70 0 0,1 0,0" fill="#710000" />
    <path d="M20,70 a50,50 0 0,1 100,0 a50,50 0 0,1 -100,0" fill="white" />
    <text class="perc" x="70" y="79" font-size="30px" text-anchor="middle">90%</text>
  </svg>
</div>

您可能会遇到上下文问题。我们不会在 for 循环中创建函数 :) 有关更多信息,您可以参考 > https://jslinterrors.com/dont-make-functions-within-a-loop. So as work around, do something like this? http://jsfiddle.net/Lrhxbc5c/

var intervals = [];

var getSetIntervalFunc = function (ii) {
  return function () {
    theta[ii] += 0.5;
    var x = Math.sin(theta[ii] * Math.PI / 180) * radius;
    var y = Math.cos(theta[ii] * Math.PI / 180) * -radius;
    var d = 'M0,0 v' + -radius + 'A' + radius + ',' + radius + ' 1 ' + ((theta[ii] > 180) ? 1 : 0) + ',1 ' + x + ',' + y + 'z';
    dark[ii].setAttribute('d', d);
    if (theta[ii] > maxTheta[ii]) {
      clearInterval(intervals[ii]);
    }
  }
};

for (var ii = 0; ii < 3; ii++) {
  intervals.push(setInterval(getSetIntervalFunc(ii), t));
}