2

このコードは、div、div(実際にはテキストボックス)、およびtarget(数値)の2つの入力を受け取ります。次に、疑似アニメーションの方法で数値をインクリメント/デクリメントします。問題は、入力の1つの形式としてjQueryスライダーを使用していることです。これにより、最初の呼び出しが終了する前に複数の呼び出しが発生する可能性があります。スライダーをすばやく上げてから、ロールアップの増加が終了する前に下げて、divを永遠にデクリメントしない限り、これは問題になりません。何が原因なのかわかりません。考え?

function rollNum(div, target) {
var contentString = $(div).val();
content = parseInt(contentString.substring(1));
if(content === target)
    return;
else if(div !== "#costMinusMSP" && div !== "#savingsWithMSP") {
    var total = rollNumTotalCost(div, target);
    rollNum("#costMinusMSP", total);
    rollNum("#savingsWithMSP", total /*- somehow find the cost here*/)
}
if(isNaN(content))
    content = 0;
var remainingChange = target - content;
if(remainingChange > 0)
    loopUp();
else
    loopDown();
function loopUp() {
    var length = remainingChange.toString().length;
    var incrementBy = 1;
    //Find how far away we are from target
    for(var i=0;i<length-1;i++)
        incrementBy *= 10;
    content += incrementBy;
    remainingChange -= incrementBy;
    $(div).val("$" + (content))
    if(content === target)
        return;
    else if(content > target) {
        $(div).val("$" + (target));
        return;
    }
    setTimeout(loopUp, 60);
}
function loopDown() {
    remainingChange = Math.abs(remainingChange);
    var length = remainingChange.toString().length;
    var decrementBy = 1;
    //Find how far away we are from target
    for(var i=0;i<length-1;i++)
        decrementBy *= 10;
    content -= decrementBy;
    remainingChange -= decrementBy;
    if(content < target) {
        $(div).val("$" + (target));
        return;
    }
    //This ensures we won't promise our clients negative values.
    if(content <= 0) {
        $(div).val("$0");
        return;
    }
    $(div).val("$" + (content))
    if(content === target)
        return;
    setTimeout(loopDown, 60);
}
}

不思議なことに、別のスライダー(無関係なdivを変更する)を調整すると、永遠の減少が修正されます。

私が試したこと:-関数がtrueに設定し、次にfalseに設定するブール値の「実行中」を作成してから戻ります。実行がtrueの場合、関数はfalseになるまで実行を続行します。これにより、ブラウザが強制終了されるか、最大スタックが達成されました。

4

1 に答える 1

42

数十年前:これを聞いてから、特に状態と複数のイベントの管理について多くのことを学びました(StackOverflowの質問を適切に行う方法は言うまでもありません)。簡単な答えは次のようになります。

var rolling = false;

function rollNum(div, target) {
  if (rolling) { return; }
  rolling = true;

  // Set rolling to false when done
}

それはすべてうまくいっていますが、ローリング中に発生したイベントはすべて無視されます。上記は、最初の調整後、数値のローリングが完了する前に行われたスライダーの変更には調整されません。さて、私(私たち?)はAngularを使用します($scope.$watchここで便利です)が、これに取り組んでいるときは存在しませんでした。目標数を渡す代わりに、スライダーのライブ値と照合してみませんか?(バニラJSの使用に注意してください、それははるかに高速です)。

var rollNum = function(textarea) {
  var content = parseInt(textarea.value.substring(1), 10)
    , target = parseInt(document.getElementById('sliderId').value, 10);

  if (content === target) {
    return;
  }

  // Roll up/down logic

  setTimeout(function() { rollNum(textarea); }, 60);
};

その他のいくつかの変更:

  • ifステートメントの後に角かっこを使用します。デバッグが簡単
  • の基数パラメータを忘れないでくださいparseInt

残念ながら、JSFiddleを含めることを考えていなかったため、ライブデモンストレーションを提供できません。

于 2014-05-23T21:39:28.937 に答える