• 列表插件的详解


    此列表插件,是用来显示后台的大数据的。比如:后台有几万条数据,需要一列一列的显示出来。但是由于是插件,所以应该能兼容各种数据的展示。有些数据的选项多,有些数据后面需要操作的按钮(操作的按钮也有可能是多个)。废话不说,直接上代码。

    function List (options) {
      this.dataResoure = options.dataResoure;      //数据源,要显示的数据
      this.key = options.key;                //主键;
      this.operateList = options.operateList;        //操作按钮的对象数组,数组里面有多少个,就有多少个操作按钮;

      //对象的格式{text:"",callback:callback,bingColums:[]};text是操作按钮的显示的文字,callback是点击按钮时,触发的方法。bingColums是callback需要操作多个属性值时,传入的属性名的数组
      this.isCheckButton = options.isCheckButton;  //在每一行前面是否有多选(或单选)按钮;true的话,就表示默认显示。
      this.bingContorlId = options.bingContorlId;  //需要将生成的HTML添加到容器元素的ID;
      this.columns = options.columns;  //列表的属性对象的数组,数组中每一项就是下面的这个对象,每个对象就代表每一行中的一个选项,数组有多少项,列表的每一行就显示多少个选项,下面的这个对象,就是一行中的一个选项。

      /*
      {
        "columnId":"",  //显示的列的ID
        "columnName":"",//显示的列的名称(一行中第一个选项)
        "titleStyle":"",  //每列标题样式
        "titleClassName":"",  //每列标题class
        "columnClassName":"",  //每列数据class
        "columnStyle":""    //每列数据样式
        "callback":event   //列内容转换回调;返回三个值,显示列的名称,显示列的ID ,当前行的数据对象

        "last":true      //看操作的选项是显示在一行的前面还是后面
      }*/
      this.onCheckbox = options.onCheckbox;   //选择框改变时,调用的方法
      this.info_templates = options.info_templates || "";    //列表头部显示的模板html
      this.page = options.page;

      //分页信息page = {count:100,总条数,pageSize:30,每页显示条数,goPageCallback,上一页下一页回调}
      this._pageIndex = 0;   //对内使用,当前页
      this.pageIndex = -1;    //对外使用,可以用它来设置当前页的值
      this._pageCount = 1;     //对内使用,总共有多少页
      this.selectBtnType = options.selectBtnType || "checkbox";  //选择框类型,单选还是多选,默认多选
      this.element = $("#" + this.bingContorlId);    //包装列表html的元素
      this.checkButtonCallback = options.checkButtonCallback || null;//单选框(或多选框)的回调,用来判断该行是否需要显示这个单选框(或多选框);
      this.ListHash = {};  //每行的数据对象的Hash,主键为key的值,假设key为id,那么json的id的值就是主键

      this.create();     //创建列表

    }

    List.prototype = {
      getSelectValue: function (flag) {
        var selectID = "";
        $("[name='" + this.key + "']").each(function () {
          if ($(this).attr("checked")) {      //如果一行的选择框被选,就取它的值,组装成1,2,3....这种格式的字符串
            selectID += (flag ? $(this).data("value") : $(this).val()) + ","
          }
        });
        selectID = selectID.length > 0 ? selectID.substr(0, selectID.length - 1) : "";   //去掉最后一个","字符,返回
        return selectID;
      },
      
      setBody: function (html) {
        this.body.html(html || ""); 
        if (this.page) {     //如果有页码,先生成页码
          this.body.append(this.getPaginationHtml());   //添加页码的html到显示数据列表的div元素中
        }
      },
      setInfo: function (data, info_templates) {   
        if (this.info.length == 0) {    //如果没有p,就返回不做任何处理,jQuery对象的length属性
          return;
        }
        this.info.html(info_templates || this.info_templates);   //否则就把用户传入的内容,放到列表项的最前面,用p元素显示
      },
      create: function () {
        this.element.empty();    //先把容器里面的html清空。
        this.wrap = $(this.getHeaderHtml()).appendTo(this.element);   //把列表的标题先生成,然后添加到容器中

        this.body = this.wrap.find(".table-body");   //找到显示数据列表的div元素
        this.info = this.wrap.filter(".table-info");   //过滤出显示用户传入的信息的p元素
        this.setBody();      //把数据生成列表
        this.setInfo();
      },
      getHeaderHtml: function () {
        var htmlTemp = [];
        htmlTemp.push(this.info_templates ? '<p class="pt_5 pb_5 table-info"></p>' : "");    //是否有传入头部模板html,有,就在列表前面加入一个p标签
        htmlTemp.push(' <div class="tablewrap" > <table cellspacing="0" class="tb_head"><tr>');    //table标签
        if (this.selectBtnType == "radio") {     //如果显示的是单选项标签,就表示第一行的第一个td不用添加input。如果是多选,需要点击时,把后面所有的行都选择上。
          htmlTemp.push('<td class="cb"></td>');      //就在行的前面添加一个td标签。
        }
        else if (this.isCheckButton) {    //如果不是单选,而是多选,就看是否支持点击第一行的第一个td,就选择后面所有的行。
          htmlTemp.push('<td class="cb"><input class="checkAll" type="checkbox" name="" /></td>');
        }
        for (var i = 0; i < this.columns.length; i++) {    //循环columns,看要显示多少个选项。
          !this.columns[i].last && htmlTemp.push('<td ' + (this.columns[i].titleStyle ? "style='" + this.columns[i].titleStyle + "'" : "") + '><div>' +         this.columns[i].columnName + '</div></td>');
        }
        if (this.operateList && this.operateList.length > 0) {   //如果有操作选项,就显示操作的选项。
          htmlTemp.push('<td ><div>' + "操作" + '</div></td>');
        }
        for (var i = 0; i < this.columns.length; i++) {
          this.columns[i].last && htmlTemp.push('<td ' + (this.columns[i].titleStyle ? "style='" + this.columns[i].titleStyle + "'" : "") + '><div>' +       this.columns[i].columnName + '</div></td>');
        }
        htmlTemp.push('</tr></table>');
        htmlTemp.push('<div class="table-body"></div></div>');     //返回:<p></p><div><table><tr></tr></table><div></div></div>,其中p是显示传入的信息的,一般用来当做列表的提示信息。第一个div是列表的最外层,table是列表的第一行,也就是列表的标题,第二个div是用来显示数据的列表的
        return htmlTemp.join("");
      },
      getPaginationHtml: function () {    //得到页码的html
        var page = this.page;
        this._pageCount = Math.ceil(page.count / page.pageSize);     //总数除以一页显示的数量
        if (this._pageCount <= 1) {    //如果只有一页,就不用显示页码
          return "";
        }
        if (this.pageIndex >= 0) {   //默认为-1
          this._pageIndex = this.pageIndex;    
        }
        var pageIndex = this._pageIndex + 1;     //_pageIndex 默认为0
        var p = this;
        var html = '<div class="pop_pager p_relative ta_r">

          <div style="left:auto; *top:-30px; right:10px;display:none;" class="pager-pop">'  

          //这个div是用户点击下面的页码(比如1/6)标识时弹出来让用户选择去到第几页的框
    + '跳转到第'+ '<input id="txt_pageIndex" type="text" class="pager_txt col_black">'+ ' 页<a class="lit_btn_on" href="javascript:void(0);" id="btnGoPage">' + "确定" + '</a> </div>'
    + '<a href="javascript:void(0);" ' + (pageIndex == 1 ? 'class="col_grey"' : '') + 'id="a_lastPage">' + "上一页" + '</a>'  

    //如果第一页,那么上一页就为灰色,代表不能点击
    + '<a href="javascript:void(0);" class="pop_pager_num"><span>' + pageIndex + '/' + this._pageCount + '</span><i class="s-down ml_5"></i></a>'
    + '<a href="javascript:void(0);" ' + (this._pageCount <= pageIndex ? 'class="col_grey"' : '') + ' id="a_nextPage">' + "下一页" + '</a></div>';
        return html;
      },
      getHtmlList: function (data) {
        var p = this;
        var htmlTemp = [];
        this.dataResoure = data || this.dataResoure;
        if (this.dataResoure) {
          for (var i = 0; i < this.dataResoure.length; i++) {
            var rows = this.dataResoure[i];    //json数据:{id:1,name:"chaojidao",age:25}
            if (!p.ListHash[rows[p.key]]) {    //假设key为id,rows[id] = 1,ListHash[1] = undefined
              p.ListHash[rows[p.key]] = rows;      p.ListHash = {1:{id:1,name:"chaojidao",age:25}},
            }
            htmlTemp.push('<div data-role="li" class="li-data-div" data-key="' + rows[p.key] + '"><table cellspacing="0" class="tb_comb"><tr>');
            if (this.isCheckButton) {
              var showCheckButton = true;//判断当前行是否需要显示选择框,默认显示;
              if (this.checkButtonCallback && !this.checkButtonCallback(rows))  //如果这条json数据,传进去返回了false,就证明不显示这个多选框
                showCheckButton = false;
              htmlTemp.push('<td class="cb">');
              htmlTemp.push(showCheckButton ? '<input type="' + (this.selectBtnType ? this.selectBtnType : 'checkbox') + '" data-value="' + (rows["id"] ? rows["id"] : "") + '" name="' + this.key + '" value="' + rows[this.key] + '" ' : '');
              if (this.chkBingColumn && showCheckButton) {
                for (var z = 0; z < this.chkBingColumn.length; z++) {
                  htmlTemp.push(this.chkBingColumn[z] + '="' + rows[this.chkBingColumn[z]] + '"');
                }
              }
              htmlTemp.push(showCheckButton ? '/>' : '');
              htmlTemp.push('</td>');
             }
            for (var j = 0; j < this.columns.length; j++) {
              var col = this.columns[j];
              var sTitle = "";
              if(rows[col.columnId]==null){        //col.columnId=id,rows[col.columnId] = 1
                sTitle = "";
              }else{
                sTitle = rows[col.columnId].toString();
              }
              if(!col.last){
                htmlTemp.push('<td ' + (col.columnClassName ? "class='" + col.columnClassName + "'" : "") + (col.titleStyle ? "style='" + col.titleStyle + "'" : "") + '><div class="tf" ' + (col.showTitle ? " title='" +sTitle + "'" : "") + '>');  

                 //如果要显示title,就显示值(因为值可能比较长,有tilte形式显示)
                htmlTemp.push(col.callback ? col.callback.call(p, rows[col.columnId], col.columnId, rows) : rows[col.columnId]);

                //如果有回调方法,就显示回调方法返回的值
                htmlTemp.push('</div></td>');
              }
            }

            if (this.operateList && this.operateList.length > 0) {
              htmlTemp.push('<td ><div>');
              var operateIndex = 0;
              for (var z = 0; z < this.operateList.length; z++) {
                var btnObj = this.operateList[z];
                var changeText = btnObj.text;
                if (btnObj.changeText) {
                  changeText = btnObj.changeText(rows);
                  if (changeText == "") {
                     continue;
                  }
                }
                htmlTemp.push('<a class="udline ' + (operateIndex != 0 ? "ml_5" : "") + '"' + (btnObj.action ? 'data-action="' + btnObj.action + '"' : '') +' data-index=' +z +' data-key="' +rows[this.key] +'" href="###" ');

                if (btnObj.bingColums && btnObj.bingColums.length > 0) {   //如果要操作多个属性值,需要把这些值先放在操作的a链接的属性上
                  for (var j = 0; j < btnObj.bingColums.length; j++) {
                    htmlTemp.push(btnObj.bingColums[j] + '="' + rows[btnObj.bingColums[j]] + '" ');
                  }

                }
                operateIndex++;
                htmlTemp.push(">");
                htmlTemp.push(changeText)
                htmlTemp.push('</a>');

              }

              htmlTemp.push("</div></td>");
            }

            for (var j = 0; j < this.columns.length; j++) {
              var col = this.columns[j];
              if (col.last) {
                htmlTemp.push('<td ' + (col.columnClassName ? "class='" + col.columnClassName + "'" : "") + (col.titleStyle ? "style='" + col.titleStyle + "'" : "") + '><div class="tf" ' + (col.showTitle ? " title='" + rows[col.columnId].toString()+ "'" : "") + '>');
                htmlTemp.push(col.callback ? col.callback.call(p, rows[col.columnId], col.columnId, rows) : rows[col.columnId]);
                htmlTemp.push('</div></td>');
              }
            }
            htmlTemp.push("</tr></table></div>");
          }
        }
        return htmlTemp.join("");
      },

      getSingData: function (id) {     //得到单条数据的值,json对象
        return this.ListHash[id];
      },

      onOperatecik: function (event) {
        var target = event.target;
        if (target.nodeName == "A" && target.getAttribute("data-index")) {  

          //只有操作按钮才会进入if语句,getAttribute得到的是字符串,也就是"0"也是true,但是数字0就会返回false。
          var index = parseInt(target.getAttribute("data-index"));
          var btn = this.operateList[index];
          key = target.getAttribute("data-key");   //key属性id的值
          if (btn.callback)
            callback = btn.callback;
          
          if (btn.bingColums) {   //如果要操作一行中的多个属性值,就传入bingColums数组,数组就代表你要操作的多个属性的名字
            backObj = {"id": key};
            for (var z = 0; z < btn.bingColums.length; z++) {
              backObj[btn.bingColums[z]] = target.getAttribute(btn.bingColums[z]);
            }
            callback.call(this, backObj);    //就会传入回调方法,多个属性值
          }
          else {
            callback && callback.call(this, key);    //只传入回调方法一个值:key的值
          }
        }
      },
      dataBind: function (data) {    //把数据生成列表
        var p = this;
        this.dataResoure = data;
        var html = p.getHtmlList();
        html = html.length > 0 ? html : "";//暂无数据
        p.setBody(html);
        p._bindEvent();
      },
      _bindEvent: function () {
        var p = this;
        this.element.click($.proxy(this.onOperatecik, this));  

        //事件委托机制,点击this.element中的子元素,就会调用onOperatecik方法,但是这个方法会做判断,只有操作按钮才会进行响应。
        var call = $(".checkAll").removeAttr("checked"),//先把标题行的选择框的checked属性去除,也就是默认不会选择,单选框这里不会取到元素

          chk = $("[name='" + p.key + "']");   //取到列表的所有行的选择框的元素
        call.bind("change", function () {     //改变标题行的选择框是否选择时执行的方法,单选框时,这里绑定无效
          var th = this;
          for (var i = 0, l = chk.length; i < l; i++) {
            chk[i].checked = th.checked;      //只要标题行的选择框有变化,就会改变列表的所有行的选择框的元素
          }
          p.onCheckbox && p.onCheckbox.call(this, p.getSelectValue());   //调用用户传入的回调方法,并把选择的值传进这个回调方法
        });
        if (this.selectBtnType == "checkbox") {   //如果是多选框,就绑定列表的每一行的选择框的change事件。
          chk.bind("change", function () {
            call[0].checked = (chk.length == chk.filter(":checked").length);    //如果列表的每行都选择上了,那么标题的选择框也会选择上。
            p.onCheckbox && p.onCheckbox.call(this, p.getSelectValue());   
          });
        }

        $("#a_lastPage").click(function () {   //上一页点击
            if (p._pageIndex <= 0) {
              return;
            }
            else {
              p._pageIndex = p._pageIndex - 1;
              $("#contentDiv", parent.document).scrollTop(0);   //由于上一页或下一页在页面的最底下,存在滚动条的问题,所以点击上一页或下一页后需要滚动到页面的最上面。contentDiv是装此列表的div的id。parent.document处理可能存在iframe的情况。
              p.page.goPageCallback(p._pageIndex, p._pageIndex * 30);   //调用用户传入的去哪一页的回调方法
            }
            return false;
        });
        $("#a_nextPage").click(function () {   //下一页点击

          if (p._pageIndex >= p._pageCount - 1) {
            return;
          }
          else {
            p._pageIndex = p._pageIndex + 1;
            $("#contentDiv", parent.document).scrollTop(0);
            p.page.goPageCallback(p._pageIndex, p._pageIndex * 30);
          }
          return false;
        });
        $("#btnGoPage").click(function () {    //去哪一页点击
          var index = $("#txt_pageIndex").val();
          if (index > p._pageCount || index < 1 || !(/^d+$/).test(index)) {
            return;
          }
          p._pageIndex = parseInt(index) - 1;
          $("#contentDiv", parent.document).scrollTop(0);
          p.page.goPageCallback(p._pageIndex, p._pageIndex * 30);
          return false;
        });
        $(".pop_pager_num").click(function () {   //弹出去哪一页的框
          $(document).unbind("click", _click).bind("click", _click);
          function _click(e) {
            var target = $(e.target);
            if (target.closest(".pop_pager").length == 0) {
              $(".pager-pop").hide();
            }
          }

          $(".pager-pop").show();
          return false;
        });
        $("#txt_pageIndex").keyup(function (event) {    //绑定键盘的enter事件,效果也是去哪一页
          if (event.keyCode == 13) {
            $("#btnGoPage").click();
            return false;
          }
        });
        $(".tb_comb").mouseover(function () {   //鼠标移到哪一行,背景颜色变化
          $(this).css("background", "#ecf1f6");
        });
        $(".tb_comb").mouseout(function () {
          $(this).css("background", "");
        });
      }
    }

    使用此插件,需要先

    var list = new List({

        "columns":[                                                 //假设json = {id:1,name:"chaojidan",age:25}

          { "showTitle":true,     //把id的值赋给id选项的title属性

            "columnId": "id",      //显示json对象数据的属性名

            "columnName":"ID"     //对应列表中的一个选项名

            "callback":function(value,key,json){ return }   //选项的名字不再是ID,而是返回的值

          },

          {        

            "columnId": "name",     //显示json对象数据的属性名

            "columnName":"姓名"   //对应列表中的一个选项名

          },

          {

            "columnId": "age",    //显示json对象数据的属性名

            "columnName":"年龄"   //对应列表中的一个选项名

          }

        ],    //就会把上面json的数据显示在列表中,列表中的每一行就是:  ID       姓名       年龄   

        "operateList": [     //操作按钮
          {
            "text": "跳转到其他页面",    

            "changeText":function(json){   return    },   //如果返回"",就不会显示这个操作链接
            "callback": function (id) {
              document.location.href = 'dan.do?sid=' + parent.gMain.sid + '&func=vas:chao&ji=' + id;
            },

            "bingColums":["name","age"],
          },
          {
            "text": "删除",
            "callback": function (id) {

              //删除此列表
            }
          }
        ],

        "key":id,

        "isCheckButton":true,   //是否有多选框
        "info_templates":"牛B的列表" ,   //在列表最前面显示的
        "bingContorlId": "listContent",    //页面上的div元素的id,此div用来显示list列表的   

        "onCheckbox": function (result) {}    //列表中的多选框,选择时,会调用此方法,result是已经选择的选项值

    })

    list.page = {
      "count": data.listCount,    //要显示的数据的总条数
      "pageSize": 30,    //一页显示多少条数据
      "goPageCallback": goPage      //上一页,下一页,去什么页,调用的方法
    };
    list.dataBind(data.obj);   //把数据传入此方法,然后生成列表,只有调用了此方法,才会显示数据列表,不然就只会显示有标题的列表。此方法会设置列表的内容,和列表的页码,不会设置列表的头内容。

    goPage方法,就会用传进来的index(要去第几页),去后台取数据,取到数据后,重新调用dataBind方法。就可以再次显示新的数据了。

    要想得到选择的列表的选项,可以使用list.getSelectValue();得到当前列表选中的行的所有key,用","分隔开。

    list.getSingData(id),得到列表中一行的属性值,也就是其中一个json对象。通过它的key(id)的值。

    加油!

  • 相关阅读:
    面向过程(或者叫结构化)分析方法与面向对象分析方法到底区别在哪里?请根据自己的理解简明扼要的回答
    当下大部分互联网创业公司为什么都愿意采用增量模型来做开发?
    0
    计算机网络
    java基础
    java 多线程编程
    java类与对象,用程序解释
    修饰符的探讨
    java学习总结02
    java day1
  • 原文地址:https://www.cnblogs.com/chaojidan/p/4158365.html
Copyright © 2020-2023  润新知