7

JavaScript と Ajax に完全に依存してデータをロードし、あるステップから次のステップへとプロセスをアニメーション化する 3 ステップのプロセスがあります。さらに複雑なことに、ステップ間のトランジション (前後) はアニメーション化されます :-(。ユーザーがプロセス アンカーを介して進行すると、現在のステップと前のステップが表示されます。前のステップをクリックすると、元のステップに戻ります。前のステップ。

現時点では、ステップ 1 から始めればプロセス全体 (順方向と逆方向) が正しく機能しますが、ステップ 3 に直接ジャンプすると、ステップ 1 とステップ 2 のアンカーもステップ 3 と同じアクションを実行します。

これは、ユーザーがいる現在のステップまでのすべてのステップをループし、各アンカーを順番に表示して、適切な関数をクリック イベントに割り当てるコードの一部です。

for (var i = 0; i < profile.current + 1; i++) {
    if ($('step_anchor_' + i).innerHTML.empty()) {
        var action = profile.steps[i].action;
        var dao_id = profile.steps[i].dao_id;

        $('step_anchor_' + i).innerHTML = profile.steps[i].anchor;
        $('step_anchor_' + i).observe('click', function(){
            pm.loadData(action, dao_id, true);
        });

        Effect.Appear('step_anchor_' + i, {
            duration: 1,
            delay: (down_delay++)
        });
    }
}

action および dao_id パラメータが渡される方法に問題があることはわかっています。また、 profile.steps[i].action および profile.steps[i].dao_id を渡そうとしましたが、その場合は profile と i の両方または少なくとも私は範囲外です。

各ステップで action と dao_id のパラメーターを正しく割り当てるにはどうすればよいですか? (違いがある場合は、Prototype と Scriptaculous を使用しています)

4

2 に答える 2

7

クロージャ スコープ チェーンが問題の原因です。ハンドラー関数をインラインで宣言することにより、クロージャーが作成されました。明らかに、ループを利用するためにこれを行いました。

ただし、クロージャーを作成したため、クロージャーのスコープ規則に従ってプレイしています。これらのルールでは、クロージャーが存在する限り、親関数内のローカル変数はアクティブであり、使用可能であると規定されています。

「アクション」と「dao_id」をクロージャーに渡して使用しようとしていますが、ここでは値ではなく参照を渡しています。したがって、クロージャー (ハンドラー) が呼び出されると、参照が最後に割り当てられた値が使用されます。あなたの場合、ステップ 3 ハンドラ。

クロージャー スコープのルールは十分にわかりにくいものですが、ループ ブロックの実行が終了しても「action」と「dao_id」がまだ有効であるという事実に混乱するかもしれません。まあ、JavaScript にはブロック スコープのようなものはありません。変数を宣言すると、関数が終了するまで、または変数が削除されるまで使用できます。いずれか早い方。

とはいえ、スコープチェーンを壊す必要があります。これを行うには、次の 2 つの方法があります。

これを試して:

for (var i = 0; i < profile.current + 1; i++) {
    if ($('step_anchor_' + i).innerHTML.empty()) {
        var action = profile.steps[i].action;
        var dao_id = profile.steps[i].dao_id;

        $('step_anchor_' + i).innerHTML = profile.steps[i].anchor;
        $('step_anchor_' + i).observe('click', function(a, b){
                return function(){pm.loadData(a, b, true)};
        }(action, dao_id));

        Effect.Appear('step_anchor_' + i, {
                duration: 1,
                delay: (down_delay++)
        });
    }
}

またはこれ:

function createHandler(action, dao_id) {
    return function(){pm.loadData(action, dao_id, true);};
} 

/* snip - inside some other function */
for (var i = 0; i < profile.current + 1; i++) {
    if ($('step_anchor_' + i).innerHTML.empty()) {
        var action = profile.steps[i].action;
        var dao_id = profile.steps[i].dao_id;

        $('step_anchor_' + i).innerHTML = profile.steps[i].anchor;
        $('step_anchor_' + i).observe('click', createHandler(action, dao_id));
        Effect.Appear('step_anchor_' + i, {
                duration: 1,
                delay: (down_delay++)
        });
    }
}
于 2008-11-24T23:31:36.133 に答える
0

まず、クリック イベントの実行スコープを覚えておいてください。そのコンテキストでのthisキーワードは、クリックされている要素を参照します。クリックされた要素から dao_id を特定する方法はありますか?

于 2008-11-24T22:38:01.920 に答える