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。