Arce 发表于 2021-6-30 19:25:24

curd组件2:按钮实现

  参考:https://blog.csdn.net/dixian4894/article/details/102209151
  上篇没有区分哪些字段可以编辑,而且如果像性别这种,在编辑的时候应该是个选择器,所以,在fields_config添加attr属性,并在attr赋值是否可编辑,编辑状态所用html标签,select的数据来源属性,一个例子如下:
      {
            "field_name": "性别",
            "field_in_db": "gender",
            "display": True,
            "show_data": "!GENDER",
            "attr": {
                "editable": True,
                "htmlLabel": "select",
                "selectDataFrom":"GENDER"
            }
      },  前端得到这些数据,便可实现,编辑,全选,反选,取消按钮,代码如下:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
    <style>
      .data-display{
            margin: 200px;
      }
</style>
</head>
<body>

    <div class="data-display">
      <div class="btn-group" role="group" aria-label="...">
          <button id="SelectAll" type="button" class="btn btn-default">全选</button>
          <button id="Reserve" type="button" class="btn btn-default">反选</button>
          <button id="Cancel" type="button" class="btn btn-default">取消</button>
          <button id="EditMode" type="button" class="btn btn-default">进入编辑模式</button>
          <button id="Del" class="btn btn-default">批量删除</button>
          <button id='save' type="button" class="btn btn-default">保存</button>
      </div>
      <table class="table table-bordered" id="Datatable">
            <thead id="table_th"></thead>
            <tbody id="table_td"></tbody>
      </table>
    </div>
</body>
<script src="/static/js/jquery-3.5.1.min.js"> </script>
<script>
    $(function () {
            initTable();
            BindEditMode();
            BindCheckboxEditMode();
            BindSelectAll();
            BindCancel();
            BindReserve();
      })
    function initTable(){
      $.ajax({
                  url:"getCurdData",
                  type:'POST',
                  dataType:'Json',
                  success:function (arg) {
                        initchoice(arg.choices_dict)
                        initThead(arg.fields_config)
                        initTbody(arg.data,arg.fields_config)
                  }
      })
    }
    function initThead(field) {
      tr_ele=$("<tr></tr>")
      $.each(field,function (k,v) {
                if(v["display"]){
                  th_ele=$("<th></th>")
                  th_ele.text(v["field_name"])
                  tr_ele.append(th_ele)
                }
                $("#table_th").append(tr_ele)
            })

    }
    function initTbody(data,field) {
      // 数据展示一般做法是,取出展示的字段,然后循环数据列表判断是否在里面,有则展示
      // 但是这么做有个缺点是数据和字段的顺序要对应(因为是以数据为顺序,而字段顺序是可能变化的),而且不利于扩展
      // 这里采用先循环数据列表,再循环field字段列表,根据字段的列表的顺序反选查找赋值
      // 缺点是多次循环field比较耗性能,但是扩展能力变强了
      $.each(data,function (data_k,data_v) {
            tr_ele=$("<tr></tr>")
            $.each(field,function (field_k,field_v) {
                if(field_v.display){
                  td_ele=$("<td></td>")
                  //赋值attr
                  $.each(field_v.attr,function (attr_k,attr_v) {
                            td_ele.attr(attr_k,attr_v)
                  })
                  if(field_v["show_data"]==='@'){
                        td_ele.html(data_v])
                  }
                  else if(field_v["show_data"]==='!'){
                        var f_v=field_v["show_data"]
                        var choice_list=f_v.substring(1,f_v.length)
                        var choice_v=value_from_choice_list(data_v],window)
                        td_ele.html(choice_v)
                  }
                  else{
                        td_ele.html(field_v["show_data"])
                  }

                  tr_ele.append(td_ele)
                }
            })
            $("#table_td").append(tr_ele)
      })
    }

    function initchoice(choice_dict) {
      $.each(choice_dict,function (i,j) {
            // a='123'相当于window='123'
            // 这里把choices列表转化为全局变量
            window=j;
      })
    }
    function value_from_choice_list(index,choice) {
      //choice格式:{0: (2) ["male", "男"],}
      //v="male",v="男"
      ret=null
      $.each(choice,function (k,v) {
            if(v === index){
                ret=v
                //js 的return只能跳出当前循环,类似shell的break
                // 所以额外赋值
                return
            }
      })
      return ret
    }
    function BindEditMode() {
      $('#EditMode').click(function () {
            //进入编辑模式,应该有个标记,才能区分进入与退出,这里用btn-info属性给button上色
            //所以也用这个属性判断是否在编辑模式,有则是应退出,无则不是应进入
            //也可以自己定义一个属性判断
            if($(this).hasClass("btn-info"))
            {
                OutEditMode()
            }else{
                IntoEditMode()
            }
      })
    }
    function IntoEditMode() {
      $('#EditMode').addClass("btn-info")
      $('#EditMode').text("退出编辑模式")
      //查找checkbox是否选中,有则查找对应tr进入编辑
      $("#table_td").find(":checked").each(function () {
            $cur_tr=$(this).parent().parent()
            TrIntoEdit($cur_tr)
      })
    }
    function OutEditMode() {
      $('#EditMode').removeClass("btn-info")
      $('#EditMode').text("进入编辑模式")
      $("#table_td").find(":checked").each(function () {
            $cur_tr=$(this).parent().parent()
            TrOutEdit($cur_tr)
      })

    }
    function TrIntoEdit(cur_tr) {
      //给当前行加个颜色表示正在编辑
      cur_tr.addClass("info")
      // 查找tr下的td含有editable属性的元素进行渲染
      cur_tr.find('').each(function () {
            var htmllabel = $(this).attr('htmllabel')
            if(htmllabel === 'select'){
                //如果类型是select,获取列表值,渲染成select选择
                var selectData=$(this).attr('selectDataFrom')
                var select_ele=$("<select></select>")
                var cur_select_v=$(this).html()
                $.each(window,function (select_k,select_v) {
                  var option_ele=$("<option></option>")
                  option_ele.val(select_v)
                  option_ele.html(select_v)
                  if(cur_select_v === select_v){
                         option_ele.attr("selected",true)
                  }
                   select_ele.append(option_ele)
                })
                $(this).html(select_ele)
            }else {
                label_v=$(this).text()
                input_ele=$("<input>")
                input_ele.val(label_v)
                $(this).html(input_ele)
            }


      })

    }
    function TrOutEdit(cur_tr) {
      //当前行去掉颜色表示退出
      cur_tr.removeClass("info")
      // 查找tr下的td含有editable属性的元素进行渲染
      cur_tr.find('').each(function () {
            var htmllabel = $(this).attr('htmllabel')
            if(htmllabel === 'select'){
                //如果类型是select,获取选中的值,赋值
                var select_ele = $(this).children().first()
                var cur_select_v=select_ele.selectedOptions.innerHTML
                $(this).html(cur_select_v)
            }else {
                var input_ele = $(this).children().first()
                var cur_input_v=input_ele.val()
                $(this).html(cur_input_v)
            }


      })

    }
    function BindCheckboxEditMode() {
      // IntoEditMode的函数有个bug,如果先进入编辑模式,再点击checkbox按钮
      // 当前行不会进入编辑模式,这是因为点击button比勾选快
      // 所以需要对CheckBox进行编辑模式下的事件委托
      $("#table_td").on('click',':checkbox',function () {
            if ($("#EditMode").hasClass("btn-info")) {
                cur_status = $(this).prop('checked');
                var $cur_tr = $(this).parent().parent();
                if(cur_status){
                  TrIntoEdit($cur_tr)
                }else{
                  TrOutEdit($cur_tr)
                }
            }
      })
    }
    function BindSelectAll() {
      // 全选分两种,编辑模式下,要TrIntoEdit,普通则勾选即可
      $('#SelectAll').click(function () {
            // 全选只需处理未被选中的即可
            $("#table_td").find(":checkbox").not(":checked").each(function () {
                if($("#EditMode").hasClass("btn-info")){
                  $(this).prop('checked',true);
                  var $cur_tr = $(this).parent().parent();
                  TrIntoEdit($cur_tr)
                }else{
                  $(this).prop('checked',true);
                }
            })
      })
    }
    function BindReserve() {
      // 反选需要两种情况,编辑模式下,如果选中则TrOutEdit,未选中则TrIntoEdit
      // 普通则反选即可
      $('#Reserve').click(function () {
            $("#table_td").find(":checkbox").each(function () {
                if($("#EditMode").hasClass("btn-info")){
                  var $cur_tr = $(this).parent().parent();
                  if($(this).prop('checked')){
                        $(this).prop('checked',false);
                        TrOutEdit($cur_tr)
                  }else{
                        $(this).prop('checked',true);
                        TrIntoEdit($cur_tr)
                  }

                }else{
                  if($(this).prop('checked')){
                        $(this).prop('checked',false);
                  }
                  else{
                        $(this).prop('checked',true);
                  }
                }
            })
      })
    }
    function BindCancel() {
      // 取消跟全选相反,只需要处理选中的checkbox
      // 也是两种情况,若编辑模式,则TrOutEdit,否则去掉勾选即可
      $('#Cancel').click(function () {
            $("#table_td").find(":checked").each(function () {
                if($("#EditMode").hasClass("btn-info")){
                  $(this).prop('checked',false);
                  var $cur_tr = $(this).parent().parent();
                  TrOutEdit($cur_tr)
                }else{
                  $(this).prop('checked',false);
                }
            })
      })
    }
</script>
</html>  在实现删除和保存的时候,需要改动的东西比较多,因为保存意味着更新,所以要知道旧值和新值,如果新旧不一样才更新,这意味着多加字段标记旧属性,修改赋值代码等,具体如下:在实现删除和保存的时候,需要改动的东西比较多,因为保存意味着更新,所以要知道旧值和新值,如果新旧不一样才更新,这意味着多加字段标记旧属性,修改赋值代码等,具体如下:
config属性赋值更新:
之前:
    "attr": {
    "editable":True,
    "htmlLabel":""
}

之后:
    "attr": {
                "editable":True,
                "origin_v":"@field_name",
                "htmlLabel":""
            }

initTbody函数修改:

tr赋值属性记录当前行id;
      之前:
          tr_ele=$("<tr></tr>")
      之后:
      tr_ele=$("<tr></tr>")
      var old_data_id=data_v["id"]
      tr_ele.attr("old_data_id",old_data_id)


td属性赋值更新:

    //赋值attr
      // 赋值field_in_db属性,用以在更新时找到对应数据库字段
            td_ele.attr("field_in_db",field_v["field_in_db"])
    $.each(field_v.attr,function (attr_k,attr_v) {
      // "origin_v":"@field_name",属性赋值需转为数据库的值
      if(attr_k==="origin_v")
      {
          attr_v=data_v]
          td_ele.attr(attr_k,attr_v)
      }else{
          td_ele.attr(attr_k,attr_v)
      }
    })


TrIntoEdit函数修改:
之前:
   cur_tr.addClass("info")
之后:
   cur_tr.addClass("info")
      // 标记当前行已编辑,表明可能数据变更,没有则没变更
      cur_tr.attr("has-edit",true)
   
TrOutEdit退出赋新值:

之前:
    var select_ele = $(this).children().first()
    var cur_select_v=select_ele.selectedOptions.innerHTML
    $(this).html(cur_select_v)

之后:
    var select_ele = $(this).children().first()
    var cur_select_v=select_ele.selectedOptions.innerHTML
    $(this).html(cur_select_v)
    // 赋新值属性
    origin_v=$(this).prop("origin_v")
    change_v=DBvalue_from_choice_list(cur_select_v,window)
    if(origin_v != change_v){
      $(this).attr("change_v",change_v)
    }
   
   
添加save 按钮:
    function BindSave() {
      // 收集改变的行,每行为一条记录,从tr标签读取旧数据id
      // 从td读取field_name作为key,读取chang_v为value,若无则不赋值
      $('#Save').click(function () {
            // 如果编辑模式下,相当于点了取消
            $('#Cancel').click()
            // 用update_list作为标记,告知后端传送的是更新的数据
            var update_list=[]
            $('#table_td').find('tr').each(function () {
                record={}
                id_v=$(this).attr("old_data_id")
                record["id"]=id_v
               $(this).children('').each(function(){
                   if($(this).attr("change_v")) {
                     field_k = $(this).attr("field_in_db")
                     field_v = $(this).attr("change_v")
                     record = field_v
                   }
                })
                update_list.push(record);
            })
            $.ajax({
                url: "getCurdData",
                type: 'POST',
                data: {'update_list': JSON.stringify(update_list)},
                dataType: 'json',
                success:function (arg) {
                  if(arg.status=='ok'){
                        initTbody()
                  }
                }
            })
      })
    }

添加删除按钮:
    function BindDel() {
      // 删除按钮要获取当前选中行的数据库id,还要弹窗提示确认
      $('#Del').click(function () {
            del_list=[]
            $('#table_td').find(":checked").each(function () {
                record={}
                // save找的是tr,这里是td,所以需parent
                id_v=$(this).parent().parent().attr("old_data_id")
                console.log($(this))
                record["id"]=id_v
            })
            del_list.push(record)
            var r=confirm("确定删除?");
            if(r){
                $.ajax({
                url: "getCurdData",
                type: 'POST',
                data: {'del_list': JSON.stringify(del_list)},
                dataType: 'json',
                success:function (arg) {
                  if(arg.status=='ok'){
                        initTbody()
                  }
                }
             })
            }
      })
    }  按钮都实现后,就可以提取共同的部分封装成js(增加功能:requestURL,用pager分页等),最终代码如下:
  后端view(无实现保存和删除)
def getCurdData(request):
    print(request.POST)
    Gender_list=list(User.GENDER)
    work_list=[('1', '开'), ('2', '关')]
    fields_config=[
      {
            "field_name": "选项",
            "field_in_db": "",
            "display": True,
            "show_data": "<input type='checkbox' />",
            "attr":{
            }
      },
      {

            "field_name":"用户名",
            "field_in_db":"username",
            "display":True,
            "show_data":"@field_name",
            "attr": {
                "editable":True,
                "origin_v":"@field_name",
                "htmlLabel":"",
            }
      },
      {
            "field_name": "密码",
            "field_in_db": "password",
            "display": True,
            "show_data": "@field_name"
      },
      {
            "field_name": "邮件",
            "field_in_db": "email",
            "display": True,
            "show_data": "@field_name",
            "attr": {
                "editable": True,
                "htmlLabel": "",
                "origin_v":"@field_name",
            }
      },
      {
            "field_name": "性别",
            "field_in_db": "gender",
            "display": True,
            "show_data": "!GENDER",
            "attr": {
                "editable": True,
                "origin_v": "@field_name",
                "htmlLabel": "select",
                "selectDataFrom":"GENDER"
            }
      },
      {
            "field_name": "电话",
            "field_in_db": "tel",
            "display": True,
            "show_data": "@field_name"
      },
      {
            "field_name": "生日",
            "field_in_db": "birthday",
            "display": True,
            "show_data": "@field_name"
      },
      {
            "field_name": "别名",
            "field_in_db": "name",
            "display": True,
            "show_data": "@field_name"
      },
    ]
    data_list=list(User.objects.all().values())

    result={
      "fields_config":fields_config,
      "data":data_list,
      "choices_dict":{
            "GENDER":Gender_list,
            "work":work_list,
      }
    }
    return HttpResponse(json.dumps(result,cls=CJsonEncoder))  删除和保存的POST数据如下:
<QueryDict: {'del_list': ['[{"id":"1"}]']}>
"POST /getCurdData HTTP/1.1" 200 1574
<QueryDict: {'update_list': ['[{"id":"1"},{"id":"2"}]']}>  CURDbyLinzb.js
   $(function () {
    function initTable(pager){
      // pager:提取第pager页的数据
      $.ajax({
                  url:requestURL,
                  type:'GET',
                  data:{'pager':pager},
                  dataType:'Json',
                  success:function (arg) {
                        initchoice(arg.choices_dict)
                        initThead(arg.fields_config)
                        initTbody(arg.data,arg.fields_config)
                  }
      })
    }
    function initThead(field) {
      tr_ele=$("<tr></tr>")
      $.each(field,function (k,v) {
                if(v["display"]){
                  th_ele=$("<th></th>")
                  th_ele.text(v["field_name"])
                  tr_ele.append(th_ele)
                }
                $("#table_th").append(tr_ele)
            })

    }
    function initTbody(data,field) {
      // save按钮重载时,会重新生成,所以需清空
         $('#table_td').empty();
      // 数据展示一般做法是,取出展示的字段,然后循环数据列表判断是否在里面,有则展示
      // 但是这么做有个缺点是数据和字段的顺序要对应(因为是以数据为顺序,而字段顺序是可能变化的),而且不利于扩展
      // 这里采用先循环数据列表,再循环field字段列表,根据字段的列表的顺序反选查找赋值
      // 缺点是多次循环field比较耗性能,但是扩展能力变强了
      $.each(data,function (data_k,data_v) {
            tr_ele=$("<tr></tr>")
            // tr赋值属性,标记当前行在数据库中的id,为更新做旧数据标记
            var old_data_id=data_v["id"]
            tr_ele.attr("old_data_id",old_data_id)
            $.each(field,function (field_k,field_v) {
                if(field_v.display){
                  td_ele=$("<td></td>")
                  // td 赋值attr
                  // 赋值field_in_db属性,用以在更新时找到对应数据库字段
                  td_ele.attr("field_in_db",field_v["field_in_db"])
                  $.each(field_v.attr,function (attr_k,attr_v) {
                            // "origin_v":"@field_name",属性赋值需转为数据库的值
                            if(attr_k==="origin_v")
                            {
                              attr_v=data_v]
                              td_ele.attr(attr_k,attr_v)
                            }else{
                              td_ele.attr(attr_k,attr_v)
                            }
                  })
                  if(field_v["show_data"]==='@'){
                        td_ele.html(data_v])
                  }
                  else if(field_v["show_data"]==='!'){
                        var f_v=field_v["show_data"]
                        var choice_list=f_v.substring(1,f_v.length)
                        var choice_v=value_from_choice_list(data_v],window)
                        td_ele.html(choice_v)
                  }
                  else{
                        td_ele.html(field_v["show_data"])
                  }

                  tr_ele.append(td_ele)
                }
            })
            $("#table_td").append(tr_ele)
      })
    }
    function initchoice(choice_dict) {
      $.each(choice_dict,function (i,j) {
            // a='123'相当于window='123'
            // 这里把choices列表转化为全局变量
            window=j;
      })
    }
    function value_from_choice_list(index,choice) {
      //choice格式:{0: (2) ["male", "男"],}
      //v="male",v="男"
      ret=null
      $.each(choice,function (k,v) {
            if(v === index){
                ret=v
                //js 的return只能跳出当前循环,类似shell的break
                // 所以额外赋值
                return
            }
      })
      return ret
    }
    function DBvalue_from_choice_list(index,choice) {
      //choice格式:{0: (2) ["male", "男"],}
      //v="male",v="男"
      ret=null
      $.each(choice,function (k,v) {
            if(v === index){
                ret=v
                //js 的return只能跳出当前循环,类似shell的break
                // 所以额外赋值
                return
            }
      })
      return ret
    }
    function BindEditMode() {
      $('#EditMode').click(function () {
            //进入编辑模式,应该有个标记,才能区分进入与退出,这里用btn-info属性给button上色
            //所以也用这个属性判断是否在编辑模式,有则是应退出,无则不是应进入
            //也可以自己定义一个属性判断
            if($(this).hasClass("btn-info"))
            {
                OutEditMode()
            }else{
                IntoEditMode()
            }
      })
    }
    function IntoEditMode() {
      $('#EditMode').addClass("btn-info")
      $('#EditMode').text("退出编辑模式")
      //查找checkbox是否选中,有则查找对应tr进入编辑
      $("#table_td").find(":checked").each(function () {
            $cur_tr=$(this).parent().parent()
            TrIntoEdit($cur_tr)
      })
    }
    function OutEditMode() {
      $('#EditMode').removeClass("btn-info")
      $('#EditMode').text("进入编辑模式")
      $("#table_td").find(":checked").each(function () {
            $cur_tr=$(this).parent().parent()
            TrOutEdit($cur_tr)
      })

    }
    function TrIntoEdit(cur_tr) {
      //给当前行加个颜色表示正在编辑
      cur_tr.addClass("info")
      // 标记当前行已编辑,表明可能数据变更,没有则没变更
      cur_tr.attr("has-edit",true)
      // 查找tr下的td含有editable属性的元素进行渲染
      cur_tr.find('').each(function () {
            var htmllabel = $(this).attr('htmllabel')
            if(htmllabel === 'select'){
                //如果类型是select,获取列表值,渲染成select选择
                var selectData=$(this).attr('selectDataFrom')
                var select_ele=$("<select></select>")
                var cur_select_v=$(this).html()
                $.each(window,function (select_k,select_v) {
                  var option_ele=$("<option></option>")
                  option_ele.val(select_v)
                  option_ele.html(select_v)
                  if(cur_select_v === select_v){
                         option_ele.attr("selected",true)
                  }
                   select_ele.append(option_ele)
                })
                $(this).html(select_ele)
            }else {
                label_v=$(this).text()
                input_ele=$("<input>")
                input_ele.val(label_v)
                $(this).html(input_ele)
            }


      })

    }
    function TrOutEdit(cur_tr) {
      //当前行去掉颜色表示退出
      cur_tr.removeClass("info")
      // 查找tr下的td含有editable属性的元素进行渲染
      cur_tr.find('').each(function () {
            var htmllabel = $(this).attr('htmllabel')
            var selectdata = $(this).attr('selectDataFrom')
            if(htmllabel === 'select'){
                //如果类型是select,获取选中的值,赋值
                var select_ele = $(this).children().first()
                var cur_select_v=select_ele.selectedOptions.innerHTML
                $(this).html(cur_select_v)
                // 赋新值属性
                origin_v=$(this).attr("origin_v")
                change_v=DBvalue_from_choice_list(cur_select_v,window)
                if(origin_v != change_v){
                  $(this).attr("change_v",change_v)
                }
            }else {
                var input_ele = $(this).children().first()
                var cur_input_v=input_ele.val()
                $(this).html(cur_input_v)
                origin_v=$(this).attr("origin_v")
                change_v=cur_input_v
                if(origin_v != change_v){
                  $(this).attr("change_v",change_v)
                }
            }


      })

    }
    function BindCheckboxEditMode() {
      // IntoEditMode的函数有个bug,如果先进入编辑模式,再点击checkbox按钮
      // 当前行不会进入编辑模式,这是因为点击button比勾选快
      // 所以需要对CheckBox进行编辑模式下的事件委托
      $("#table_td").on('click',':checkbox',function () {
            if ($("#EditMode").hasClass("btn-info")) {
                cur_status = $(this).prop('checked');
                var $cur_tr = $(this).parent().parent();
                if(cur_status){
                  TrIntoEdit($cur_tr)
                }else{
                  TrOutEdit($cur_tr)
                }
            }
      })
    }
    function BindSelectAll() {
      // 全选分两种,编辑模式下,要TrIntoEdit,普通则勾选即可
      $('#SelectAll').click(function () {
            // 全选只需处理未被选中的即可
            $("#table_td").find(":checkbox").not(":checked").each(function () {
                if($("#EditMode").hasClass("btn-info")){
                  $(this).prop('checked',true);
                  var $cur_tr = $(this).parent().parent();
                  TrIntoEdit($cur_tr)
                }else{
                  $(this).prop('checked',true);
                }
            })
      })
    }
    function BindReserve() {
      // 反选需要两种情况,编辑模式下,如果选中则TrOutEdit,未选中则TrIntoEdit
      // 普通则反选即可
      $('#Reserve').click(function () {
            $("#table_td").find(":checkbox").each(function () {
                if($("#EditMode").hasClass("btn-info")){
                  var $cur_tr = $(this).parent().parent();
                  if($(this).prop('checked')){
                        $(this).prop('checked',false);
                        TrOutEdit($cur_tr)
                  }else{
                        $(this).prop('checked',true);
                        TrIntoEdit($cur_tr)
                  }

                }else{
                  if($(this).prop('checked')){
                        $(this).prop('checked',false);
                  }
                  else{
                        $(this).prop('checked',true);
                  }
                }
            })
      })
    }
    function BindCancel() {
      // 取消跟全选相反,只需要处理选中的checkbox
      // 也是两种情况,若编辑模式,则TrOutEdit,否则去掉勾选即可
      $('#Cancel').click(function () {
            $("#table_td").find(":checked").each(function () {
                if($("#EditMode").hasClass("btn-info")){
                  $(this).prop('checked',false);
                  var $cur_tr = $(this).parent().parent();
                  TrOutEdit($cur_tr)
                }else{
                  $(this).prop('checked',false);
                }
            })
      })
    }
    function BindSave() {
      // 收集改变的行,每行为一条记录,从tr标签读取旧数据id
      // 从td读取field_name作为key,读取chang_v为value,若无则不赋值
      $('#Save').click(function () {
            // 如果编辑模式下,相当于点了取消
            $('#Cancel').click()
            // 用update_list作为标记,告知后端传送的是更新的数据
            var update_list=[]
            $('#table_td').find('tr').each(function () {
                record={}
                id_v=$(this).attr("old_data_id")
                record["id"]=id_v
               $(this).children('').each(function(){
                   if($(this).attr("change_v")) {
                     field_k = $(this).attr("field_in_db")
                     field_v = $(this).attr("change_v")
                     record = field_v
                   }
                })
                update_list.push(record);
            })
            $.ajax({
                url: requestURL,
                type: 'POST',
                data: {'update_list': JSON.stringify(update_list)},
                dataType: 'json',
                success:function (arg) {
                  if(arg.status=='ok'){
                        initTbody(1)
                  }
                }
            })
      })
    }
    function BindDel() {
      // 删除按钮要获取当前选中行的数据库id,还要弹窗提示确认
      $('#Del').click(function () {
            del_list=[]
            $('#table_td').find(":checked").each(function () {
                record={}
                // save找的是tr,这里是td,所以需parent
                id_v=$(this).parent().parent().attr("old_data_id")
                if(id_v!=undefined) {
                  record["id"] = id_v
                  del_list.push(record)
                }
            })
            var r=confirm("确定删除?");
            if(r){
                $.ajax({
                url: requestURL,
                type: 'POST',
                data: {'del_list': JSON.stringify(del_list)},
                dataType: 'json',
                success:function (arg) {
                  if(arg.status=='ok'){
                        initTbody(1)
                  }
                }
             })
            }
      })
    }
    jQuery.extend({
      'CreateCURD':function (url) {
                  requestURL = url;
                  initTable(1);
                  BindEditMode();
                  BindCheckboxEditMode();
                  BindSelectAll();
                  BindCancel();
                  BindReserve();
                  BindSave();
                  BindDel();
                },
      'TurnToPager':function (num) {
                  inittable(num);
                }
            })
    })  前端代码:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
    <style>
      .data-display{
            margin: 200px;
      }
</style>
</head>
<body>

    <div class="data-display">
      <div class="btn-group" role="group" aria-label="...">
          <button id="SelectAll" type="button" class="btn btn-default">全选</button>
          <button id="Reserve" type="button" class="btn btn-default">反选</button>
          <button id="Cancel" type="button" class="btn btn-default">取消</button>
          <button id="EditMode" type="button" class="btn btn-default">进入编辑模式</button>
          <button id="Del" class="btn btn-default">批量删除</button>
          <button id='Save' type="button" class="btn btn-default">保存</button>
      </div>
      <table class="table table-bordered" id="Datatable">
            <thead id="table_th"></thead>
            <tbody id="table_td"></tbody>
      </table>
    </div>
</body>
<script src="/static/js/jquery-3.5.1.min.js"> </script>
<script src="/static/js/CURDbyLinzb.js"> </script>
<script>
   $(function () {
            $.CreateCURD( 'getCurdData')
      })
</script>
</html>
  
页: [1]
查看完整版本: curd组件2:按钮实现