1. 程式人生 > >ajax渲染頁面點選事件失效的解決方法

ajax渲染頁面點選事件失效的解決方法

問題所在:

最近在學習使用JQ中ajax方法來渲染頁面資料,填充表格,附上ajax獲取資料填充表格的程式碼:

$.ajax({
        //請求方式
            type:'GET',
            //傳送請求的地址以及傳輸的資料
            url:"https://www.easy-mock.com/mock/5bd5c6b982302f7129a2809c/example/mock",
            //伺服器返回的資料型別
            async : false,
            dataType:'json',
            success:function(data) {
                var thead = "<thead><tr><th><input type='checkbox' id='select-all'></th>"
                var tbody = "<tbody>";
                var th = "";
                var tr = "";
                //thead部分
                $.each(data.data.colum,function (key,value) {
                            th = "<th>"+value+"</th>";
                            thead += th;
                        });//完成thead的組裝,取的是data->data->colum的value
                
                        var rowArr = data.data.row;//行陣列
                        var colArr = data.data.colum;//列陣列
                        for(var i=0;i<rowArr.length;i++){
                        tr += "<tr><td><input type='checkbox'></td>";
                                var sumObj = data.data.dataContent[rowArr[i]];
                                if(sumObj){
                                    for(var k in sumObj){
                                        tr += "<td>"+sumObj[k]+"</td>";
                                    }
                                }
                        tr += "<td class='operating'><button class='edit-button'><span>編輯</span></button > <button class='delete-button'><span>刪除</span></button></td></tr>";
                    }
                    tbody += tr;
                $('.table').append(thead+tbody);
                
            },
           
            error:function(jqXHR){
                //請求失敗函式內容
                alert("ERROR");
            }
        });

從程式碼中可以看到我通過拼接字串 來完成table的組裝,其中使用ajax從後臺獲取資料。那麼要實現一個自定義的表格,必定離不開元件、id和class的使用,而這些也是需要在拼接字串中完成。

於是問題來了,我在通過ajax組裝完成表格後,我之前全部的點選事件都失效了。附上全選框和排序功能的程式碼。

/*全選框*/
$(function(){
    $("#select-all").click(function() { 
            
    if (this.checked){  
        $("tbody input[type='checkbox']").each(function(i){ 
            $(this).prop("checked", true); 
        });
    } else {   
        $("tbody input[type='checkbox']").each(function() {   
            $(this).prop("checked", false);  
            console.log($(this).attr("checked"));
        });
    }  
})
});
/*點選列表頭排序功能*/
$(function() {  /*入口函式,等待dom渲染完畢之後才執行*/
        var sort_direction=1; //排序標誌,1為升序,-1為降序
        $('th').each(function(i) {
            $(this).click(function() {
                if(sort_direction==1) {
                    sort_direction=-1;
                }
                else {
                    sort_direction=1;
                }
                //獲得行陣列
                var trarr=$('table').find('tbody > tr').get();
                //陣列排序
                trarr.sort(function(a, b) {
                    var col1=$(a).children('td').eq(i).text().toUpperCase(); 
                    var col2=$(b).children('td').eq(i).text().toUpperCase();
                    return(col1 < col2) ? -sort_direction: (col1 > col2) ? sort_direction: 0;
                }
                );
                $.each(trarr, function(i, row) {
                    //將排好序的陣列重新填回表格
                    $('tbody').append(row);
                }
                );
            }
            );
        }
        ); 
});

 入口函式

先不說解決辦法,我們看看載入事件:

JavaScript的入口函式要等到頁面中所有資源(包括圖片、檔案)載入完成才開始執行。 jQuery的入口函式只會等待文件樹載入完成就開始執行,並不會等待圖片、檔案的載入。

JQ和JS中還有load方法,用於等待頁面中資源完全載入,再執行相應程式碼。JQ入口函式等待DOM載入完成便可以執行程式碼。 

事件委託

事件委託,通俗地來講,就是把一個元素響應事件(click、keydown......)的函式委託到另一個元素;

一般來講,會把一個或者一組元素的事件委託到它的父層或者更外層元素上,真正繫結事件的是外層元素,當事件響應到需要繫結的元素上時,會通過事件冒泡機制從而觸發它的外層元素的繫結事件上,然後在外層元素上去執行函式。

 個人理解,事件委託是把一個事件委託到(繫結到)某一元素上,等到此元素被捕獲的時候可以完成對應事件。

沒錯,事件委託的其中一個優點就是動態繫結事件,可以為“未來元素”繫結好事件。

在很多時候,我們需要通過 AJAX 或者使用者操作動態的增加或者去除列表項元素,那麼在每一次改變的時候都需要重新給新增的元素繫結事件,給即將刪去的元素解綁事件;

如果用了事件委託就沒有這種麻煩了,因為事件是繫結在父層的,和目標元素的增減是沒有關係的,執行到目標元素是在真正響應執行事件函式的過程中去匹配的;

所以使用事件在動態繫結事件的情況下是可以減少很多重複工作的。

問題初探

事實上事件的機制不難理解,JQ中無非就是幾個方法的實現:

  • $.on: 基本用法: $('.parent').on('click', 'a', function () { console.log('click event on tag a'); }),它是 .parent 元素之下的 a 元素的事件代理到 $('.parent') 之上,只要在這個元素上有點選事件,就會自動尋找到 .parent 元素下的 a 元素,然後響應事件;
  • $.delegate: 基本用法: $('.parent').delegate('a', 'click', function () { console.log('click event on tag a'); }),同上,並且還有相對應的 $.delegate 來刪除代理的事件;
  • $.live: 基本使用方法: $('a', $('.parent')).live('click', function () { console.log('click event on tag a'); }),同上,然而如果沒有傳入父層元素 $(.parent),那事件會預設委託到 $(document) 上;(已廢除)

我試過用live(存活)方法修改全選框功能的點選觸發,確實有效,但是我發現對於我的排序功能,需要獲取每一個表格th,然而渲染完成前後排序程式碼已經開始執行了,當然獲取不到,這就不是點選事件那麼簡單了。

非同步和同步

注意我上面加粗的那段文字,表格通過ajax渲染的同時,其他的程式碼一直在執行,這就是ajax非同步的一種體現。

非同步:在ajax請求的同時其他程式碼仍然可以執行。

同步:與排隊同理,ajax請求完成之前其他的程式碼處於排隊狀態,頁面假死,等待ajax完成之後執行其他程式碼。

解決方法

所以理論上需要將ajax換為同步通訊,就可以讓其他功能不受影響。

async : false; //同步

只要一行程式碼,當然,功能需要在同步+dom載入完成的基礎上才可以真正實現,也就是click事件還是要放在入口函式之中。

有沒有其他辦法呢?據我看來還有很多可行的辦法,我還沒有試過,比如說在組裝表格的時候為標籤加上onClick,然後把功能寫進function之中,點選事件執行function。