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。

 

参考文献(知乎):https://zhuanlan.zhihu.com/p/26536815

 

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值