1. 程式人生 > 其它 >【學習筆記】JS 在迴圈中設定監聽事件並使用 ajax 設定動態新增的元素的值時出現的問題及其解決方案

【學習筆記】JS 在迴圈中設定監聽事件並使用 ajax 設定動態新增的元素的值時出現的問題及其解決方案

問題

for(var i = 1 ; i <= 10 ; i ++) { // 注意迴圈變數 i
    var newLine = "<tr>";
    newLine += "<td><input type='text' id='sampleInput" + i + "'></td>";
    newLine += "<td><span id='sampleSpan" + i + "'></td>";
    newLine += "</tr>";
    // 動態為 newLine 追加 HTML,id 與迴圈變數有關
    
    $("#sampleTable tbody").append(newLine);
    // 往已存在的 table 中新增新的這一行
    
    $("#sampleInput" + i).on("input", function(){ //這裡設定的監聽物件是沒問題的,能夠實現對於 sampleInput i 的監聽
        $.ajax({
            type: "get",
            url: "sampleAction",
            // data: {}, 假裝這裡有傳別的值
            success: function(data){
                // data = eval("(" + data + ")");
                $("#sampleSpan" + i).html(data); // 這裡想修改 sampleSpan i 的值
            }
        });
    });
}

上面這一段 \(JS\) 程式碼,意圖是往 \(sampleTable\) 中插入十行,每行一個文字框 \(sampleInput\{i\}\) 和一個行內元素 \(sampleSpan\{i\}\)

然後對於每行的文字框,只要觸發了 \(input\) 事件就向後臺傳送請求,將獲取到的資料在同一行的行內元素上顯示出來


但這段程式碼的事實卻是,不論修改哪個文字框,行內元素都沒有效果


實際上在 \(ajax\)\(success\) 匿名函式裡看看 \(i\) 的值就清楚了,加一行 \(alert\) 輸出,發現所有 \(i\) 的值都是 \(11\)

這是因為 \(ajax\) 只有執行完請求且獲得資料後才會執行 \(success\)

匿名函式,這一部分與迴圈是非同步執行的,也就是說在執行這個函式的時候可能外頭的 \(for\) 迴圈已經結束了(終值就是 \(11\)

而在函式內呼叫 \(i\) 這個變數是通過地址去取值的,並沒有把執行 \(ajax\) 時的 \(i\) 的值快取下來,才會出現上面的這種情況


這裡可能有人會說,我直接把 \(ajax\) 的非同步關了就是了 async: false

所以上面的例子裡在外層套了個監聽

監聽事件觸發的時候迴圈肯定是執行完了的,與這個非同步沒有關係


解決

解決方法,把需要的值通過 \(ajax\) 傳給後端,讓後端重新傳回來,問題解決(簡單粗暴)

因為傳入值時還沒有開始非同步執行,引用的 \(i\)

是會快取當時的值的

for(var i = 1 ; i <= 10 ; i ++) {
    var newLine = "<tr>";
    newLine += "<td><input type='text' id='sampleInput" + i + "'></td>";
    newLine += "<td><span id='sampleSpan" + i + "'></td>";
    newLine += "</tr>";
    
    $("#sampleTable tbody").append(newLine);
    
    $("#sampleInput" + i).on("input", function(){
        $.ajax({
            type: "get",
            url: "sampleAction",
            data: {id: i}, // 把需要的值 i 傳給後端
            success: function(data){
                data = eval("(" + data + ")");
                var i = data.id; // 讓 action 再把它返回來就是了
                $("#sampleSpan" + i).html(data.data);
            }
        });
    });
}

後記:

挺奇妙的,在 debug 的時候竟然沒有遇到“無法找到動態新增的元素”的問題

本來我是往這個方向想的,於是就捨棄了通過 id 來查詢元素,換了其他麻煩的方法(相對位置檢索大法)

然後重新回來看這個問題,越看越奇怪,於是輸出了一下迴圈變數,直接豁然開朗……