首页 > 代码库 > 列表插件的详解
列表插件的详解
此列表插件,是用来显示后台的大数据的。比如:后台有几万条数据,需要一列一列的显示出来。但是由于是插件,所以应该能兼容各种数据的展示。有些数据的选项多,有些数据后面需要操作的按钮(操作的按钮也有可能是多个)。废话不说,直接上代码。
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="http://www.mamicode.com/‘ + (rows["id"] ? rows["id"] : "") + ‘" name="‘ + this.key + ‘" value="http://www.mamicode.com/‘ + 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="http://www.mamicode.com/###" ‘);
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 = http://www.mamicode.com/‘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)的值。
加油!
列表插件的详解