自己写一个轻量的JqueryGrid组件
接触mvc不久,突然没有了viewstate和服务端控件处处都觉得不顺手,很多在webform时不必要考虑的问题都出现在眼前,这其中分页时查询条件保持的问题又是最让我头疼的事情,权衡再三,决定用ajax局部刷新列表的方式来解决这个问题。网上基于jquery的grid组件很多,jquerygrid,jqgrid等等,分别试用了一下,功能确实非常强大,但感觉上有点重,配置项太多,用起来依然感觉束手束脚,所以想来想去,还是用最笨的办法自己做了一个组件,很简陋,唯一的好处就是灵活,容易修改和控制。
没图没真相,先来个截图看看:
功能:
- 指定url,支持post或get方式加载数据
- 自定义数据查询条件
- 列定义时可以对数据项进行简单的转换处理。如:数据源[{ "name": "张三", "age": 12, "sex": 1 }],渲染时希望把sex的值 1 显示为 男性
- 支持多选
- 支持分页
- 点击行时自动选中,多选时,点击checkbox进行选中和取消选中
- 能够返回选中项目的值,多选时返回选中值的数组
根据个人的习惯和对功能的分解,定义了这样一个setting:
var list = $('#list').GridView({
'apiUrl': '/Student/List', // 指定数据请求的URL路径
'apiType': 'post', // 请求的方式
'columns': [ // 要显示的列,title对应表头,column对应数据项的属性名称,width指定列的宽度,func指定绑定时调用的函数名称
{ title: '姓名', column: 'Name', width: 160 },
{ title: '年龄', column: 'Age' },
{ title: '性别', column: 'Sex', width: 100, 'func': 'convertToSex' }
],
'valueColumn': 'StudentId', // data-value 取值的属性名
'pageSize': 20, // 每页显示的数量
'isMultiy': false, // 是否支持多选
'isTreeView': false, // 是否支持树形
'pager': 'pager', // 指定包含分页的divid,主要是为了能单独控制pager中的一些数据,把pager给拆出来了,后来发现似乎用处不大
'onRowClick': function(id) { }, // 当数据行被点击时执行的回调,参数是tr中的data-value
'convertSource': function (data) { return data.body; }, // 使用数据源之前对数据进行转换。因为我的api返回的都是{ code: 200, body: [] }这种类型,需要在这里直接返回body
'onDataBindComplete': function() {}, // 当数据加载完成,也就是列表渲染完成后的回调。比如说提醒用户加载完成之类的
'getSearchData': function() { return $('#form1').serialize(); }, // 获取查询参数,这个很重要,想了很多办法,最终采用了这种方案,在查询前运行这个函数,将返回值作为ajax的查询参数
'listCssClass': 'table', // 列表table的样式名
'pagerCssClass': 'pager', // 分页最外面div的样式名
'beforeSend': function() { } // ajax请求之前调用的函数,原本是为了提醒一下加载已开始,请稍后之类的,现在没怎么用到
});
OK,接下来就是这个扩展的具体实现了,代码很多,但思路很简单,主要就是代码的拼接。大家自己看吧!
(function ($) { $.fn.GridView = function (settings) {
// 系统变量
var self = this;
self.selected = [];
var pageindex = 1, pageSize = 20; if (settings.pageSize && $.isNumeric(settings.pageSize) && settings.pageSize > 0) {
pageSize = settings.pageSize;
} var rand = Math.floor(Math.random() * 1000);
var table = $("<table" + (settings.listCssClass ? " class='" + settings.listCssClass + "'" : "") + " id='myList" + rand + "'></table>"); var colgroup = colgroup2 = "<colgroup>"
$.each(settings.columns, function (idx, item) {
colgroup += "<col" + item.width ? " style='width:" + item.width + "px;'" : "" + ">";
colgroup2 += "<col" + item.width ? " style='width:" + item.width + "px;'" : "" + ">";
});
colgroup += "<col style='width:18px;'></col>";
colgroup += "</colgroup>";
colgroup2 += "</colgroup>";
var table = $("<table" + (settings.listCssClass ? " class='" + settings.listCssClass + "'" : "") + " id='myList" + rand + "'></table>"); var pagerHtml = '<div' + (!settings.pagerCssClass ? '' : ' class="' + settings.pagerCssClass + '"') + '>';
//var pagerHtml = '';
pagerHtml += '<a class="disabled" id="first' + rand + '"><i class="fa fa-fast-backward"></i></a>';
pagerHtml += '<a class="disabled" id="prev' + rand + '"><i class="fa fa-backward"></i></a>';
pagerHtml += '<div class="pager-index"><b>第</b><input value="1" type="text" maxlength="4" id="index' + rand + '"><b>页</b></div>';
pagerHtml += '<a class="disabled" id="next' + rand + '"><i class="fa fa-forward"></i></a>';
pagerHtml += '<a class="disabled" id="last' + rand + '"><i class="fa fa-fast-forward"></i></a>';
pagerHtml += '<div class="pager-info2"> 共计 <span class="totalCount" id="total' + rand + '">0</span> 条记录,';
pagerHtml += '每页显示 <span class="pageSize' + rand + '">' + pageSize + '</span> 条,';
pagerHtml += '共 <span class="totalPage" id="page' + rand + '">1</span> 页,';
pagerHtml += '用时 <span class="loadTime" id="time' + rand + '">0</span>毫秒';
pagerHtml += "</div></div>";
var pagerDom = $(pagerHtml);
var firstButton, prevButton, nextButton, lastButton, currentSpan, pageSizeSpan, totalCountSpan, totalPagesSpan, loadTimeSpan; // 临时变量
var tbody, pager, cbAll, checkboxes, isPager = false, totalPage = 1; // 创建table
self.append(table); // 创建thead
addChildrenToTable(); // 为tbody赋值
tbody = $("#tbody" + rand); var colCount = settings.columns.length + 2;
tbody.html("<tr class='empty'><td colspan='" + colCount + "'>等待加载数据...</td></tr>"); // 创建分页
if (settings.pager && $("#" + settings.pager)[0]) {
pager = $("#" + settings.pager);
isPager = true;
pager.append(pagerDom);
setPagerButtonEvent();
} // 创建渲染函数
self.fun = new Function("data", renderFunString()); // 渲染第一列
self.setFirstCol = function (val) {
if (settings.isMulti) {
return "<td class='chk'><input type='checkbox' id='cb" + val + "' value='" + val + "'></td>"
} else {
return "<td class='no'>" + val + "</td>";
}
} // 渲染最后一列
self.setLastCol = function () {
return "<td></td>";
} // 渲染中间列
self.setCol = function (content, width, cssClass, level) {
var html = "<td";
html += width ? " style='width:" + width + "px'" : "";
html += cssClass && cssClass != 'undefined' ? " class='" + cssClass + "'" : "";
html += ">";
if (settings.isTreeView) {
html += level ? "<span class='block' style='width:" + 24 * level + "px'>" + (level > 0 ? "|—" : "") + "</span>" : "";
}
html += content && content != "undefined" ? content : "";
html += "</td>";
return html;
} // 显示指定页码的数据
self.show = function (index, type) {
self.selected = [];
if (!settings.apiUrl) {
return;
} if (!type || type.toLowerCase() != "post") {
$.get(settings.apiUrl, getAjaxData(), function (data) {
var source = [];
if (settings.convertSource && $.isFunction(settings.convertSource)) {
source = settings.convertSource(data);
} else {
source = data;
}
addRowsToTbody(source);
});
} else {
$.post(settings.apiUrl, getAjaxData(), function (data) {
var source = [];
if (settings.convertSource && $.isFunction(settings.convertSource)) {
source = settings.convertSource(data);
} else {
source = data;
}
addRowsToTbody(source);
});
}
}; // 获取选中的ID
self.getSelectedId = function () {
if (self.selected.length == 0) {
return null;
} else {
return self.selected[0];
}
}; self.getSelectedIds = function () {
return self.selected;
}; self.clear = function () {
self.selected = [];
$("tr", "#myList" + rand).removeClass("selected");
$(":checkbox", "#myList" + rand).prop("checked", false);
}; // 为table内的元素绑定事件
tbody.on("click", "tr", function () {
if ($(this).hasClass("empty")) return;
$("tr", tbody).removeClass("selected").find(":checkbox").prop("checked", false);
$(this).addClass("selected").find(":checkbox").prop("checked", true);
$("#cbAll" + rand).prop("checked", false);
self.selected = [$(this).data("value")];
}); // 绑定复选框点击事件
if (settings.isMulti) {
cbAll = $("#cbAll" + rand); cbAll.on("click", function () {
if (!checkboxes) checkboxes = $(":checkbox", tbody); if ($(this).prop("checked")) {
self.selected = []; $.each(checkboxes, function (idx, item) {
$(this).prop("checked", true);
self.selected.push($(this).val()); var tr = $("#tr" + $(item).val());
if (!tr.hasClass("selected")) tr.addClass("selected");
});
} else {
checkboxes.prop("checked", false);
$("tr", tbody).removeClass("selected");
self.selected = [];
}
}); tbody.on("click", ":checkbox", function (event) {
event.stopPropagation(); if ($(this).prop("checked")) {
$("#tr" + $(this).val()).addClass("selected");
} else {
$("#tr" + $(this).val()).removeClass("selected");
}
if (!checkboxes) {
checkboxes = $(":checkbox", tbody);
} self.selected = []; var unCheckedCount = 0; $.each(checkboxes, function () {
if ($(this).prop("checked")) {
self.selected.push($(this).val());
} else {
unCheckedCount++;
}
}); if (unCheckedCount > 0) {
cbAll.prop("checked", false);
} else {
cbAll.prop("checked", true);
}
});
} // 返回渲染函数的程序体
function renderFunString() {
var funString = "var self = this; var html = ''; $.each(data, function(idx, item) { var val = ";
funString += (settings.valueColumn ? "item." + settings.valueColumn : "idx");
funString += "; html += '<tr id=\"tr' + val + '\" data-value=\"' + val + '\">'; html += self.setFirstCol(val);";
var level = null;
if (settings.levelColumn) {
level = settings.levelColumn;
}
$.each(settings.columns, function (idx, item) {
if (item.func) {
funString += " html += self.setCol( " + item.func + "(item), " + item.width + ", '" + item.cssClass + "'" + (level ? " , item." + level : "") + " );";
} else {
funString += " html += self.setCol( item." + item.column + ", " + item.width + ", '" + item.cssClass + "'" + (level ? " , item." + level : "") + " );";
}
});
funString += " html += self.setLastCol(); html += '</tr>'; idx++; }); return html;";
return funString;
} // 将数据生成html,并插入到tbody中
function addRowsToTbody(data) {
if (data && data.body && data.body.length > 0) {
var html = self.fun(data.body);
tbody.html(html); if (isPager) {
setPagerButton(pageSize, pageindex, data.totalCount, new Date().getTime());
}
} else {
var colCount = settings.columns.length + 2;
tbody.html("<tr class='empty'><td colspan='" + colCount + "'>请求的数据为空</td></tr>");
}
} // 创建table
function addChildrenToTable() {
var body = "<thead>"
if (settings.columns) {
if (settings.isMulti) {
body += "<th class='chk'><input type='checkbox' id='cbAll" + rand + "' /></th>";
} else {
body += "<th class='no'></th>";
} $.each(settings.columns, function (idx, col) {
body += "<th>" + col.title + "</th>";
});
body += "<th></th>";
body += "</thead><tbody id='tbody" + rand + "'></tbody>"; table.append($(body));
}
} // 绑定分页按钮的点击事件
function setPagerButtonEvent() {
firstButton = $("#first" + rand);
prevButton = $("#prev" + rand);
nextButton = $("#next" + rand);
lastButton = $("#last" + rand);
currentSpan = $("#index" + rand); pageSizeSpan = $("#size" + rand);;
totalCountSpan = $("#total" + rand);;
totalPagesSpan = $("#page" + rand);;
loadTimeSpan = $("#time" + rand);; firstButton.on("click", function () {
if (!$(this).hasClass("disabled")) {
pageindex = 1;
self.show();
}
}); prevButton.on("click", function () {
if (!$(this).hasClass("disabled")) {
pageindex -= 1;
pageindex = pageindex <= 0 ? 1 : pageindex;
self.show();
}
}); nextButton.on("click", function () {
if (!$(this).hasClass("disabled")) {
pageindex += 1;
self.show();
}
}); lastButton.on("click", function () {
if (!$(this).hasClass("disabled")) {
pageindex = totalPage;
self.show();
}
}); currentSpan.on("change", function () {
var nc = Number($(this).val());
if (nc && nc <= totalPage && nc > 0) {
pageindex = nc;
self.show();
} else {
$(this).val(pageindex);
}
});
} // 配置 Pager 按钮
function setPagerButton(size, index, total, start) {
if (total == 0) {
pager.hide();
} else {
pager.show();
} // 总页数
var pages = Math.ceil(total / size);
pages = (pages == 0 ? 1 : pages);
totalPage = pages; if (pages == 1) {
if (!firstButton.hasClass("disabled")) {
firstButton.addClass("disabled");
}
if (!prevButton.hasClass("disabled")) {
prevButton.addClass("disabled");
}
if (!nextButton.hasClass("disabled")) {
nextButton.addClass("disabled");
}
if (!lastButton.hasClass("disabled")) {
lastButton.addClass("disabled");
}
} else {
if (index == 1) {
if (!firstButton.hasClass("disabled")) {
firstButton.addClass("disabled");
}
if (!prevButton.hasClass("disabled")) {
prevButton.addClass("disabled");
}
} else {
if (firstButton.hasClass("disabled")) {
firstButton.removeClass("disabled");
}
if (prevButton.hasClass("disabled")) {
prevButton.removeClass("disabled");
}
}
currentSpan.val(index);
if (index == pages) {
if (!nextButton.hasClass("disabled")) {
nextButton.addClass("disabled");
}
if (!lastButton.hasClass("disabled")) {
lastButton.addClass("disabled");
}
} else {
if (nextButton.hasClass("disabled")) {
nextButton.removeClass("disabled");
}
if (lastButton.hasClass("disabled")) {
lastButton.removeClass("disabled");
}
}
}
totalCountSpan.text(total);
pageSizeSpan.text(this.pageSize);
totalPagesSpan.text(pages);
loadTimeSpan.text((new Date().getTime() - start));
} // 获取ajax的查询参数
function getAjaxData() {
var param;
if ($.isFunction(settings.getSearchData)) {
param = settings.getSearchData();
}
if (isPager) {
if ($.isArray(param)) { // $("form").serializationArray()
param.push({ "name": "pageSize", "value": pageSize });
param.push({ "name": "pageIndex", "value": pageindex });
} else if ($.isPlainObject(param)) { // 自定义查询对象
$.extend(true, param, { "pageSize": pageSize, "pageIndex": pageindex });
} else { // $("form").serialization()
param = (param ? param + "&" : "") + "pageSize=" + pageSize + "&pageIndex=" + pageindex;
}
}
return !!param ? param : {};
} return self;
} })(jQuery); /*
*使用范例:
*==========================数据格式============================
{
"code": 200,
"describe": "",
"totalCount": 3,
"body": [
{
"no": 1,
"name": "王五",
"family": {
"father": "王老五",
"mother": "陈静蓉"
}
},
{
"no": 2,
"name": "张三",
"family": {
"father": "张作霖",
"mother": "李培芳"
}
},
{
"no": 3,
"name": "李四",
"family": {
"father": "李宗仁",
"mother": "江少芬"
}
}
]
} *==========================页面调用============================
<script src="jquery-1.10.2.js"></script>
<script src="myGrid.js"></script>
<script>
var list = $("#list").myGrid({
apiUrl: "data.json",
isMulti: false,
isTree: true,
cols: [
{ col: "no", width: 120, title: "编号", cssClass: "chk", level: 0 },
{ col: "name", width: 120, title: "姓名", level: 0 },
{ col: "family.father", width: 120, title: "父亲", level: 1, func: "addFix" }
],
valueCol: "no",
pager: "pager",
pageSize: 2,
cssClass: "default-list-table",
convertSource: function(data) {
return data;
}
}); // 这个是用来转换数据的方法
function addFix(obj) {
return "000" + obj;
}
list.show();
</script>
一个修改的操作:
自己写一个轻量的JqueryGrid组件的更多相关文章
- vue-concise-slider 一个轻量的vue幻灯片组件
vue-concise-slider 一个轻量的vue幻灯片组件 阅读 541 收藏 35 2017-07-03 原文链接:github.com 外卖订单处理有烦恼?试试美团点评餐饮开放平台吧,可实现 ...
- 对 JDBC 做一个轻量封装,待完善。。。
对 JDBC 做一个轻量地封装,顺便复习,熟悉sql,io,util,lang.Reflect等包的使用,泛型的使用,待完善... package com.webproj.utils; import ...
- Day.js 是一个轻量的处理时间和日期的 JavaScript 库
Day.js 是一个轻量的处理时间和日期的 JavaScript 库,和 Moment.js 的 API 设计保持完全一样. 如果您曾经用过 Moment.js, 那么您已经知道如何使用 Day.js ...
- Nancy总结(一)Nancy一个轻量的MVC框架
Nancy是一个基于.net 和Mono 构建的HTTP服务框架,是一个非常轻量级的web框架. 设计用于处理 DELETE, GET, HEAD, OPTIONS, POST, PUT 和 PATC ...
- BlockCanary 一个轻量的,非侵入式的性能监控组件(阿里)
开发者博客: BlockCanary — 轻松找出Android App界面卡顿元凶 开源代码:moduth/blockcanary BlockCanary对主线程操作进行了完全透明的监控,并能输出有 ...
- 曹工说Tomcat4:利用 Digester 手撸一个轻量的 Spring IOC容器
一.前言 一共8个类,撸一个IOC容器.当然,我们是很轻量级的,但能够满足基本需求.想想典型的 Spring 项目,是不是就是各种Service/DAO/Controller,大家互相注入,就组装成了 ...
- 利用vue写一个复选框的组件
HTML <multicheck :source=tlist :busValue='objInfo.tt' @getTt="getTtInfo"></multic ...
- 使用Hexo建立一个轻量、简易、高逼格的博客
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_93 在之前的一篇文章中,介绍了如何使用Hugo在三分钟之内建立一个简单的个人博客系统,它是基于go lang的,其实,市面上还有一 ...
- 在项目管理中如何保持专注,分享一个轻量的时间管理工具【Flow Mac版 - 追踪你在Mac上的时间消耗】
在项目管理和团队作业中,经常面临的问题就是时间管理和优先级管理发生问题,项目被delay,团队工作延后,无法达到预期目标. 这个仿佛是每个人都会遇到的问题,特别是现在这么多的内容软件来分散我们的注意力 ...
随机推荐
- 分布式锁(Zookeeper实现)
分布式锁 分布式锁,这个主要得益于 ZooKeeper 为我们保证了数据的强一致性.锁服务可以分为两类,一个是 保持独占,另一个是 控制时序. 1. 所谓保持独占,就是所有试图来获取这个锁的客户端,最 ...
- C#入门---2、C#装备知识(C#创建桌面程序的时候创建的是什么应用程序)
C#入门---2.C#装备知识(C#创建桌面程序的时候创建的是什么应用程序) 一.总结 一句话总结: WPF应用程序:来替代 WindowsFroms 来创建桌面应用程序 1.什么是控制台程序 Con ...
- Android Developers - Training
Recently I've been contemplating to create a new App with the true "Android Design",new An ...
- Spring 事务管理高级应用难点剖析: 第 3 部分
本文是“Spring 事务管理高级应用难点剖析” 系列文章的第 3 部分,作者将继续深入剖析在实际 Spring 事务管理应用中容易遇见的一些难点,包括在使用 Spring JDBC 时如果直接获取 ...
- c++之函数值传递和引用传递解析----关键在于理解函数return的实现机制(内存分配)
函数调用过程解析 func里的a存储在调用fun函数时开辟的栈空间里,这块栈只在调用func时对func可用,调用结束后返回的a,其实是暂存在寄存器里的(一般情况下是eax),而返回到main里时,m ...
- Java原子属性更新器AtomicReferenceFieldUpdater的使用
AtomicReferenceFieldUpdater是基于反射的工具类,用来将指定类型的指定的volatile引用字段进行原子更新,对应的原子引用字段不能是private的.通常一个类volatil ...
- 4.oracle正确卸载步骤
oracle 11g如何完全卸载 方法/步骤1: 停用oracle服务:进入计算机管理,在服务中,找到oracle开头的所有服务,右击选择停止 方法/步骤2: 在开始菜单中,找到oracle-> ...
- 201621123016 《Java程序设计》第十三周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 为你的系统增加网络功能(购物车.图书馆管理.斗地主等)-分组完成 为了让你的系统可以被多个用户通过网 ...
- zepto+mui开发中的tap事件重复执行
zepto.js和mui一起使用的时候,因为都有tap事件绑定tab事件后会多次触发还会报错,这时不引用zepto中的touch.js就可以了,只用mui的tap相关事件. $(function () ...
- 算法学习--Day6
题目描述 实现一个加法器,使其能够输出a+b的值. 输入描述: 输入包括两个数a和b,其中a和b的位数不超过1000位. 输出描述: 可能有多组测试数据,对于每组数据, 输出a+b的值. 示例1 输入 ...