使用 jQuery/javascript 停止条形动画

Stop bar animation with jQuery/javascript

对 JS 完全陌生,jQuery 在这里。代码遍历每个条形,当您按下 Reset 按钮时,它应该将条形缩小为零。但是,我试图让这个条形图动画停止,但是一旦你按下按钮,它就会通过动画并再次重置回之前的位置。如有任何帮助,我们将不胜感激!

function barGraph(data) {

  //Create graph
  var graph = document.createElement("div");
  graph.id = "barGraph";

  //inserting bar graph before previous 'label' div
  const target = document.querySelector('#labels');
  target.parentNode.insertBefore(graph, labels);

  //Styling for graph
  graph.style.position = "relative";
  graph.style.marginTop = "20px";
  graph.style.height = "500px";
  graph.style.backgroundColor = "Gainsboro";
  graph.style.borderBottomStyle = "solid";
  graph.style.borderBottomWidth = "1px";
  graph.style.overflow = "hidden";

  //Iterating through each bar
  var position = 50;
  var width = 75;
  for (i = 0; i < data.length; i += 1) {
    var spendData = data[i];
    var bar = document.createElement("div");
    //set a unique id for each of the bars
    bar.id = data[i].category;

    //Styling for bar
    bar.style.position = "absolute";
    bar.style.left = position + "px";
    bar.style.width = width + "px";
    bar.style.backgroundColor = spendData.color;
    bar.style.height = (spendData.amount) / 5 + "px";
    bar.style.bottom = "0px";
    bar.innerHTML = "$" + spendData.amount;
    bar.style.fontSize = "11px";
    bar.style.color = "Azure";
    bar.style.fontWeight = "800";
    bar.style.fontFamily = "Arial, Helvetica, sans-serif";
    bar.style.textAlign = "center";
    bar.style.padding = "1em";

    //Appending to the graph
    graph.appendChild(bar);

    //Set bar width
    position += (width * 2);
  }

  return graph;
}

window.onload = function() {
  var data = [{
      category: "Food and Dining",
      amount: "2005.00",
      color: "CadetBlue"
    },
    {
      category: "Auto and Transport",
      amount: "1471.31",
      color: "CornflowerBlue"
    },
    {
      category: "Shopping",
      amount: "892.86",
      color: "DarkCyan"
    },
    {
      category: "Bills and Utilities",
      amount: "531.60",
      color: "DarkSeaGreen"
    },
    {
      category: "Mortgage",
      amount: "1646.00",
      color: "LightSeaGreen"
    },
    {
      category: "Entertainment",
      amount: "179.52",
      color: "YellowGreen"
    }
  ];

  document.getElementById("resetGraph").addEventListener("click", function() {
    for (i = 0; i < data.length; i++) {
      var bar = document.getElementById(data[i].category);
      if (bar) {
        bar.animate({
          "height": "0px",
          "padding": "0px"
        }, 2000);
      }
    }
  });

  var graph = barGraph(data);
  //document.div.appendChild(graph);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="labels"></div>
<button id="resetGraph">Reset graph</button>
<script src="js/spending-graph.js"></script>

已更新

有趣的问题! AFAICT 问题是你混淆了 jQuery's .animate() with the native Javascript .animate().

你的问题被标记为 jQuery-animate,你明确地提到了它,你传递给 .animate() 的参数格式正是 jQuery 所期望的。

但是您的动画代码 运行ning 是针对 HTML DOM 元素,而不是 jQuery 元素:

// bar here is an HTML DOM Element, not a jQuery object:
var bar = document.getElementById(data[i].category);

// That means this will run JS .animate, not jQuery's:
bar.animate( ... );

如果您只是针对 jQuery 对象将其更改为 运行,它(几乎)会按预期工作:

var bar = $('#' + data[i].category);
bar.animate( ... );

我说差不多因为还有一个问题:

bar.id = data[i].category;

这会根据您的纯英文类别创建 HTML ID,其中包括空格,例如“Food and Dining”。 According to the spec:

id's value must not contain whitespace (spaces, tabs etc.).

至少在尝试使用带空格的 ID 作为 jQuery 选择器时,这很重要,但它不起作用。因此,我们只使用数组索引,它也保证是唯一的,带有前缀,这样我们就知道我们指的是什么:

bar.id = 'bar-' + i;

这是包含这 2 处更改的工作片段。

注意:最后一个 document.div.appendChild(graph); 抛出错误 - 也许这是一次调试尝试,没有必要,我已在此处注释掉它。

function barGraph(data) {

  //Create graph
  var graph = document.createElement("div");
  graph.id = "barGraph";

  //inserting bar graph before previous 'label' div
  const target = document.querySelector('#labels');
  target.parentNode.insertBefore(graph, labels);

  //Styling for graph
  graph.style.position = "relative";
  graph.style.marginTop = "20px";
  graph.style.height = "500px";
  graph.style.backgroundColor = "Gainsboro";
  graph.style.borderBottomStyle = "solid";
  graph.style.borderBottomWidth = "1px";
  graph.style.overflow = "hidden";

  //Iterating through each bar
  var position = 50;
  var width = 75;
  for (i = 0; i < data.length; i += 1) {
    var spendData = data[i];
    var bar = document.createElement("div");
    //set a unique id for each of the bars
    // UPDATED - category includes spaces, just use array index
    // bar.id = data[i].category;
    bar.id = 'bar-' + i;

    //Styling for bar
    bar.style.position = "absolute";
    bar.style.left = position + "px";
    bar.style.width = width + "px";
    bar.style.backgroundColor = spendData.color;
    bar.style.height = (spendData.amount) / 5 + "px";
    bar.style.bottom = "0px";
    bar.innerHTML = "$" + spendData.amount;
    bar.style.fontSize = "11px";
    bar.style.color = "Azure";
    bar.style.fontWeight = "800";
    bar.style.fontFamily = "Arial, Helvetica, sans-serif";
    bar.style.textAlign = "center";
    bar.style.padding = "1em";

    //Appending to the graph
    graph.appendChild(bar);

    //Set bar width
    position += (width * 2);
  }

  return graph;
}

window.onload = function() {
  var data = [{
      category: "Food and Dining",
      amount: "2005.00",
      color: "CadetBlue"
    },
    {
      category: "Auto and Transport",
      amount: "1471.31",
      color: "CornflowerBlue"
    },
    {
      category: "Shopping",
      amount: "892.86",
      color: "DarkCyan"
    },
    {
      category: "Bills and Utilities",
      amount: "531.60",
      color: "DarkSeaGreen"
    },
    {
      category: "Mortgage",
      amount: "1646.00",
      color: "LightSeaGreen"
    },
    {
      category: "Entertainment",
      amount: "179.52",
      color: "YellowGreen"
    }
  ];

  document.getElementById("resetGraph").addEventListener("click", function() {
    for (i = 0; i < data.length; i++) {
      // UPDATED: 1. use new format ID without spaces
      // UPDATED: 2. use jQuery selector/animation
      // UPDATED: 3. use bar.length to test if selector matched anything
      var bar = $('#bar-' + i);
      if (bar.length) {
        bar.animate({
          "height": "0px",
          "padding": "0px"
        }, 2000);
      }
    }
  });

  var graph = barGraph(data);
  //document.div.appendChild(graph);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="labels"></div>
<button id="resetGraph">Reset graph</button>

那么您的原始代码中发生了什么?我不知道。 Javascript.animate()是运行ning的原生,不是jQuery的。 Javascipt .animate() method的第一个参数应该是:

Either an array of keyframe objects, or a keyframe object whose properties are arrays of values to iterate over.

您的代码传递的是一个对象,而不是数组,因此 .animate() 会期望后者,即“关键帧对象”。 Keyframe Formats 规范提供了更多细节和一些“关键帧对象”的示例:

element.animate({
  opacity: [ 0, 1 ],          // [ from, to ]
  color:   [ "#fff", "#000" ] // [ from, to ]
}, 2000);

您的对象不符合此格式 - 每个属性只是一个字符串,而不是 start/stop 值的数组。关键帧文档还描述了 Implicit to/from keyframes:

In newer browser versions, you are able to set a beginning or end state for an animation only (i.e. a single keyframe), and the browser will infer the other end of the animation if it is able to.

我猜这就是正在发生的事情,不知何故?浏览器正在推断起始值的隐式结束帧?

我尝试更新您的代码以使用正确的关键帧格式,因此您可以使用本机 .animate() 并一起跳过 jQuery,但它不起作用 - 条形重置为它们的动画后的原始高度,就像你原来的代码一样,我不知道为什么:

document.getElementById("resetGraph").addEventListener("click", function() {
    var bar, startHeight;

    for (i = 0; i < data.length; i++) {
        bar = document.getElementById('bar-' + i);
        if (bar) {
            startHeight = window.getComputedStyle(bar).height;
            bar.animate({
              height: [startHeight, '0px'],
              padding: ['1em', '0']
            }, 2000);
        }
    }
});

Dom 的 animate() 函数将 return 一个 AnimationPlaybackEvent 对象。我们可以使用 onFinish 方法来重置 dom 元素的高度和宽度或者隐藏它。

您能否在 bar.animate() 函数后添加以下行到您的代码中。

.onfinish=function(e){
        e.currentTarget.effect.target.style.visibility ="hidden"
    };

喜欢下面的片段。

bar.animate({
      "height": "0px",
      "padding": "0px"
    }, 2000).onfinish=function(e){
        e.currentTarget.effect.target.style.visibility ="hidden"
    };