用于后台管理的列表数据控件:DataGrid和Select
常听人说不喜欢javascript。然而我一个一直用C#做后端的人,最喜欢的编程语言就是javascript了,我接收它的优点,也接收它的缺点!
前段时间接触过easyui,用过里面的DataGrid和Combobox等控件,感觉DataGrid的确减少了一些重复的工作,但是easyui改变原有的Element,比如textbox,不能用$("#id").val()获取值了,只能用$(“#id”).textbox('getValue')来获取,不喜欢这样。国庆放假,票到3号了,今天有时间就根据使用easyui的感觉写了两个数据控件DataGrid和Select。
先看看最后结果和前段代码:

HTML:
文章类型:
<div class="input-control select">
<select id="type" data-url="/home/TypeList"></select>
</div>
<div class="input-control text" style="width:300px;">
<input type="text" placeholder="请输入关键字" id="keyword" />
<button class="button" onclick="search()"><span class="mif-search"></span></button>
</div>
<table id="tblist" class="table border bordered" data-url="/home/PageData">
<thead>
<tr>
<th data-field="$index"></th>
<th data-field="ID">编号</th>
<th data-field="Title">标题</th>
<th data-field="Type" data-url="/home/TypeList">类型</th>
<th data-field="Author">作者</th>
<th data-field="AddTime">添加时间</th>
<th data-field="_operator" data-formatter="operateFormatter">操作</th>
</tr>
</thead>
</table>
JavaScript:
<script src="~/Scripts/jquery.min.js"></script>
<script src="~/js/data-widget.js"></script>
<script>
var dg = new dw.DataGrid($('#tblist'));
var type = new dw.Select($("#type"));
function search() {
dg.search({ keyword: $("#keyword").val(), type: $("#type").val() });
}
function operateFormatter(value, item) {
return '<a href="##" onclick="alert(' + item.ID + ')">修改</a>';
}
</script>
Select数据控件:
id为type的select元素上有个data-url的属性,这个表示加载数据的地址,这个地址必须返回一个拥有ID和Name属性的对象数组的json格式,如下:
[{ID: 1, Name: "类型1"}, {ID: 2, Name: "类型2"}, {ID: 3, Name: "类型3"}, {ID: 4, Name: "类型4"},…]
在实例化dw.Select对象的时候,第一个参数是select元素的jquery对象,上面用$('type')得到,第二个是可选参数,说明如下:
{
value: undefined, // 加载过数据选中的值
onInit: undefined, // 初始化完成后执行的函数,用加载的数据作为参数
hasDefault: true, // 是否有默认选项
defaultName: '请选择', // 默认选项显示名
defaultID: '' // 默认选项值
}
DataGrid数据控件:
id为tblist的table元素可有三个自定义属性:
- data-url : 要加载数据的后台地址;
- data-page-size : 每页显示多少条数据,默认是10,会作为查询参数的pageSize;
- data-page-index : 加载时显示第几页,默认是1,会作为查询参数的pageIndex(可能永远也用不到,感觉默认值1很合理......);
data-url后台地址返回的格式应该如下:
{
PageCount : 100 //总页数 --int,
PageIndex : 1 //当前页 --int,
List : [
{ID:1, Title : '标题1' ,AddTime : "/Date(1332919782070)/" },
......
] // 分页数据列表---Array
}
在实例化dw.DataGrid对象的时候,第一个参数是table元素的jquery对象,上面用$('tblist')得到,第二个是查询参数,可选。
在thead里定义表头,每个th表示一列,th可有四个自定义属性:
- data-field:返回数据列表的对象属性名,必须;
- data-formatter : 该列的格式化器,用于修改这列数据的显示形式,比如性别是bool,可以显示成“男”或“女”,比如上面例子中_operator列,虽然不对应任何字段,但是可以显示自定义的内容
- data-format : 目前用于日期格式(“/Date(1332919782070)/”)的字符串(注意是字符串类型,但是是日期格式),默认值是:“yyyy-MM-dd hh:mm”
- data-url : 用于从ID映射成对应的Name,比如文章列表的文章类型Type返回的是类型ID,可以提供这个url返回数据,控件自动映射成类型名称,从html大号字的两个地方可以看出,地址和Select的data-url是一样的。
DataGrid对象有个search方法,参数是查询参数,用法如上。
注:加红的“查询参数”是指同一个东西,这个参数会加上pageIndex和pageSize一起post到table的data-url地址来查询数据。我用asp.net mvc做的例子中的后台Action方法签名如下:
, )
注:Select的data-url和Type列的data-url相同,在内部是有缓存的,所以加载这部分数据的时候用的是同步ajax,从加载效果可以看出只加载了一次,缓存生效了:

data-widget.js依赖jQuery;
data-widget.js源码如下:
;/*
file: data-widget.js
author: loogn
date : 2016-10-1
descript: DataGrid、Select、Pager
*/
var dw = (function () {
var dw = {};
//根据url缓存 ,没有的话要同步获取
dw.cache = {};
dw.getCache = function (url) {
var key = url.toLowerCase();
var data = dw.cache[key];
if (data) return data;
$.ajax({
url: url,
type: 'POST',
async: false,
success: function (result) {
dw.cache[key] = result;
data = result;
}
});
return data;
}
var styleArr = [];
//pager.css
styleArr.push('table .page a{ text-decoration:none; font-weight:normal;}');
styleArr.push('table .page span{ text-decoration:none; font-weight:normal;}');
styleArr.push('table .page a:hover{ text-decoration:none;}');
styleArr.push('table .page{padding: 15px 20px;text-align: left;color: #ccc;}');
styleArr.push('table .page a{display: inline-block;color: #428bca;display: inline-block;height: 25px; line-height: 25px; padding: 0 10px;border: 1px solid #ddd; margin: 0 2px;border-radius: 4px;vertical-align: middle;}');
styleArr.push('table .page span.current{display: inline-block;height: 25px;line-height: 25px;padding: 0 10px;margin: 0 2px;color: #fff;background-color: #428bca; border: 1px solid #428bca;border-radius: 4px;vertical-align: middle;}');
styleArr.push('table .page a:hover{text-decoration: none;border: 1px solid #428bca;}');
styleArr.push('table .page span.disabled{ display: inline-block;height: 25px;line-height: 25px;padding: 0 10px;margin: 0 2px; color: #bfbfbf;background: #f2f2f2;border: 1px solid #bfbfbf;border-radius: 4px;vertical-align: middle;}');
var style = $('<style>').text(styleArr.join(''));
$('head').append(style);
//dateFormat(new Date(),'yyyy-MM-dd hh:mm:ss')
dw.dateFormat = function (date, format) {
var o = {
"M+": date.getMonth() + 1, //month
"d+": date.getDate(), //day
"h+": date.getHours(), //hour
"m+": date.getMinutes(), //minute
"s+": date.getSeconds(), //second
"q+": Math.floor((date.getMonth() + 3) / 3), //quarter
"S": date.getMilliseconds() //millisecond
}
if (/(y+)/.test(format)) {
format = format.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(format)) {
format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
}
}
return format;
}
//得到指定url参数
dw.getQueryString = function (name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", 'i');
var r = window.location.search.substr(1).match(reg);
if (r !== null)
return unescape(decodeURIComponent(r[2]));
return null;
};
//得到所有url参数对象
dw.getQueryObject = function () {
var args = {};
var query = location.search.substring(1);
var pairs = query.split("&");
for (var i = 0; i < pairs.length; i++) {
var pos = pairs[i].indexOf('=');
if (pos == -1) continue;
var name = pairs[i].substring(0, pos);
var value = pairs[i].substring(pos + 1);
value = decodeURIComponent(value);
args[name.toLowerCase()] = value;
}
return args;
};
return dw;
}());
(function (dwName, dw) {
function Pager($wrap, pageCount, current, onPageChange) {
this.$wrap = $wrap;
this.pageCount = pageCount;
this.current = current || 1;
this.onPageChange = onPageChange || function () { };
this.bindEvent();
this.render(pageCount, current);
}
Pager.prototype.render = function (pageCount, current) {
this.pageCount = pageCount;
this.current = current;
if (pageCount <= 1) {
this.$wrap.empty();
return;
}
//上一页
var htmlArr = [];
if (current > 1) {
htmlArr.push('<a href="javascript:;" class="prevPage">上一页</a>');
} else {
htmlArr.push('<span class="disabled">上一页</span>');
}
//中间页码
if (current != 1 && current >= 4 && pageCount != 4) {
htmlArr.push('<a href="javascript:;" class="tcdNumber">' + 1 + '</a>');
}
if (current - 2 > 2 && current <= pageCount && pageCount > 5) {
htmlArr.push('<span>...</span>');
}
var start = current - 2, end = current + 2;
if ((start > 1 && current < 4) || current == 1) {
end++;
}
if (current > pageCount - 4 && current >= pageCount) {
start--;
}
for (; start <= end; start++) {
if (start <= pageCount && start >= 1) {
if (start != current) {
htmlArr.push('<a href="javascript:;" class="tcdNumber">' + start + '</a>');
} else {
htmlArr.push('<span class="current">' + start + '</span>');
}
}
}
if (current + 2 < pageCount - 1 && current >= 1 && pageCount > 5) {
htmlArr.push('<span>...</span>');
}
if (current != pageCount && current < pageCount - 2 && pageCount != 4) {
htmlArr.push('<a href="javascript:;" class="tcdNumber">' + pageCount + '</a>');
}
//下一页
if (current < pageCount) {
htmlArr.push('<a href="javascript:;" class="nextPage">下一页</a>');
} else {
this.$wrap.remove('.nextPage');
htmlArr.push('<span class="disabled">下一页</span>');
}
//修改表现
this.$wrap.html(htmlArr.join(''));
}
Pager.prototype.bindEvent = function () {
var pager = this;
this.$wrap.on("click", "a.tcdNumber", function () {
var current = parseInt($(this).text());
pager.render(pager.pageCount, current);
if (typeof (pager.onPageChange) == "function") {
pager.onPageChange(current);
}
});
//上一页
this.$wrap.on("click", "a.prevPage", function () {
var current = parseInt(pager.$wrap.children("span.current").text());
pager.render(pager.pageCount, current - 1);
if (typeof (pager.onPageChange) == "function") {
pager.onPageChange(current);
}
});
//下一页
this.$wrap.on("click", "a.nextPage", function () {
var current = parseInt(pager.$wrap.children("span.current").text());
pager.render(pager.pageCount, current + 1);
if (typeof (pager.onPageChange) == "function") {
pager.onPageChange(current);
}
});
}
dw.Pager = Pager;
}('Pager', dw));
(function (dwName, dw) {
function DataGrid($table, params) {
this.name = dwName;
this.$table = $table; //表格对象
this.url = $table.data('url'); //加载数据的url
this.pageSize = $table.data('page-size') || 10; // 每页大小
this.pageIndex = $table.data('page-index') || 1; //当前页码
this.columns = []; //列数据
this.params = {}; //查询参数
this.pager = null;//分页控件
this.isSearch = false;
var $this = this;
$table.find('thead>tr>th').each(function () {
var $th = $(this);
var field = $th.data('field');
if (field == "$index") {
if (!$th.attr("style") || $th.attr("style").indexOf("width") < 0) {
$th.css("width", "20px");
}
}
$this.columns.push({ field: field, formatter: $th.data('formatter'), format: $th.data('format'), url: $th.data('url') });
});
//分页
$table.append('<tfoot><tr><td colspan="' + this.columns.length + '" class="page"></td></tr></tfoot>');
this.load(params);
}
//加载数据
DataGrid.prototype.load = function (params) {
params = params || {};
this.params = params;
params.pageIndex = this.pageIndex;
params.pageSize = this.pageSize;
var $this = this;
$.post(this.url, params, function (data) {
$this.render(data);
});
};
DataGrid.prototype.search = function (params) {
this.pageIndex = 1;
this.isSearch = true;
this.load(params);
}
DataGrid.prototype.render = function (data) {
var $datagrid = this;
var html_arr = [];
html_arr.push('<tbody>');
for (var i = 0; i < data.List.length; i++) {
var item = data.List[i];
html_arr.push('<tr>');
for (var j = 0; j < $datagrid.columns.length; j++) {
var column = this.columns[j];
html_arr.push('<td>');
if (column.field == "$index") {
html_arr.push(this.pageSize * (this.pageIndex - 1) + i + 1);
} else {
var renderValue = getRenderValue(item, column);
html_arr.push(renderValue);
}
html_arr.push('</td>');
}
html_arr.push('</tr>');
}
html_arr.push('</tbody>');
var tbody = $datagrid.$table.find('tbody');
if (tbody.length > 0) {
tbody.replaceWith(html_arr.join(''));
if (this.isSearch) {
$datagrid.pager.render(data.PageCount, data.PageIndex);
this.isSearch = false;
}
} else {
$datagrid.$table.append(html_arr.join(''));
//分页
this.pager = new dw.Pager($datagrid.$table.find('.page'), data.PageCount, data.PageIndex, function (num) {
$datagrid.pageIndex = num;
$datagrid.load($datagrid.params);
})
}
};
function urlMapping(id, list) {
for (var i = 0; i < list.length; i++) {
var item = list[i];
if (id == item.ID) {
return item.Name;
}
}
return '';
}
function getRenderValue(item, column) {
var val = item[column.field];
if (column.formatter) {
return eval(column.formatter + '(val,item)');
}
else if (column.url) {
var list = dw.getCache(column.url);
return urlMapping(val, list);
}
else {
if (typeof (val) === "string") {
if (/Date\([\d+]+\)/.test(val)) {
var date = eval(val.replace(/\/Date\((\d+)\)\//gi, "new Date($1)"));
val = dw.dateFormat(date, column.format || 'yyyy-MM-dd hh:mm');
return val;
}
}
return val;
}
}
dw.DataGrid = DataGrid;
}('DataGrid', dw));
(function (dwName, dw) {
function Select($select, params) {
this.name = dwName;
var args = $.extend({
value: undefined,
onInit: undefined,
hasDefault: true,
defaultName: '请选择',
defaultID: ''
}, params);
this.$select = $select;
var url = $select.data('url');
var list = dw.getCache(url);
fillSelect(list);
//[{ID:id,Name:name}]
function fillSelect(list) {
var htmlArr = [];
if (args.hasDefault) {
htmlArr.push('<option value="' + args.defaultID + '">' + args.defaultName + '</option>');
}
for (var i = 0; i < list.length; i++) {
var item = list[i];
htmlArr.push('<option value="' + item.ID + '">' + item.Name + '</option>');
}
$select.html(htmlArr.join(''));
if (args.value !== undefined) {
$select.val(args.value);
}
if (args.onInit && typeof (args.onInit) === "function") {
args.onInit(list);
}
}
}
dw.Select = Select;
}('Select', dw));
data-widget.js
用于后台管理的列表数据控件:DataGrid和Select的更多相关文章
- VS2010/MFC编程入门之二十九(常用控件:列表视图控件List Control 下)
上一节是关于列表视图控件List Control的上半部分,简单介绍了列表视图控件,其通知消息的处理和有关结构体的定义.本节继续讲解下半部分,包括列表视图控件的创建.CListCtrl类的主要成员函数 ...
- MFC常用控件之列表视图控件(List Control)
近期学习了鸡啄米大神的博客,对其中的一些知识点做了一些自己的总结.不过,博客内容大部分来自鸡啄米.因此,这个博客算是转载博客,只是加了一些我自己的理解而已.若想学习鸡啄米大神的博客总结,请点击连接:h ...
- VS2010-MFC(常用控件:列表视图控件List Control 下)
转自:http://www.jizhuomi.com/software/197.html 上一节是关于列表视图控件List Control的上半部分,简单介绍了列表视图控件,其通知消息的处理和有关结构 ...
- ASP.NET Web数据控件
ASP.NET Web数据控件 1.数据控件简介 这包括数据源控件和格式设置控件,前者使您可以使用 Web 控件访问数据库中的数据,后者使您可以显示和操作ASP.NET 网页上的数据. 2.数据控件 ...
- 用于列出选项的Windows窗体控件
可以提供选项列表的控件有ListBox.ComboBox.CheckedListBox,如何正确的使用和选择这些控件,下面对此进行讨论.首先对这三种控件的功能分别进行说明: ListBox ListB ...
- ASP.NET数据控件
数据服务器控件就是能够显示数据的控件,与那些简单格式的列表控件不同,这些控件不但提供显示数据的丰富界面(可以显示多行多列数据并根据用户定义来显示),还提供了修改.删除和插入数据的接口. ASP.NET ...
- 浅析五大ASP.NET数据控件
转自:http://kb.cnblogs.com/page/69207/ 摘要:ASP.NET中有不少的控件,在这当中有一部分是用来处理数据的控件.在这里我们正要讨论的就是ASP.NET数据控件,希望 ...
- VS2010/MFC编程入门之二十八(常用控件:列表视图控件List Control 上)
前面一节中,鸡啄米讲了图片控件Picture Control,本节为大家详解列表视图控件List Control的使用. 列表视图控件简介 列表视图控件List Control同样比较常见, ...
- Jquery如何序列化form表单数据为JSON对象 C# ADO.NET中设置Like模糊查询的参数 从客户端出现小于等于公式符号引发检测到有潜在危险的Request.Form 值 jquery调用iframe里面的方法 Js根据Ip地址自动判断是哪个城市 【我们一起写框架】MVVM的WPF框架(三)—数据控件 设计模式之简单工厂模式(C#语言描述)
jquery提供的serialize方法能够实现. $("#searchForm").serialize();但是,观察输出的信息,发现serialize()方法做的是将表单中的数 ...
随机推荐
- Web系统的常用测试方法
在51上看到一篇不错的文章,拿过来分享一下,学习学习! Web系统的常用测试方法如下: 1. 页面链接检查:每一个链接是否都有对应的页面,并且页面之间切换正确. 2. 相关性检查:删除/增加一项会不会 ...
- reactjs 接入数据模型以及markdown语法的支持
页面如下: reactjs 数据接入,直接定义数据(json),如下: reactjs 数据接入,从服务器抓取数据(json),如下:
- 用jdbc访问二进制类型的数据
package it.cast.jdbc; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; impor ...
- 禁用nested loop join里的spool
禁用nested loop join里的spool 转载自: https://blogs.msdn.microsoft.com/psssql/2015/12/15/spool-operator-and ...
- 安装jdk
检查已安装jdk,如果有,先删除 rpm -qa|grep java rpm -e --nodeps filename 从oracle官方网站下载jdk安装包:jdk-8u111-linux-x64. ...
- 探索c#之函数创建和闭包
阅读目录: 动态创建函数 匿名函数不足之处 理解c#中的闭包 闭包的优点 动态创建函数 大多数同学,都或多或少的使用过.回顾下c#中动态创建函数的进化: C# 1.0中: public delegat ...
- 玩转Windows服务系列——无COM接口Windows服务启动失败原因及解决方案
将VS创建的Windows服务项目编译生成的程序,通过命令行 “服务.exe -Service”注册为Windows服务后,就可以通过服务管理器进行管理了. 问题 通过服务管理器进行启动的时候,发现服 ...
- 玩转Windows服务系列——Windows服务小技巧
伴随着研究Windows服务,逐渐掌握了一些小技巧,现在与大家分享一下. 将Windows服务转变为控制台程序 由于默认的Windows服务程序,编译后为Win32的窗口程序.我们在程序启动或运行过程 ...
- js模块化历程
这是一篇关于js模块化历程的长长的流水账,记录js模块化思想的诞生与变迁,展望ES6模块化标准的未来.经历过这段历史的人或许会感到沧桑,没经历过的人也应该知道这段历史. 无模块时代 在ajax还未提出 ...
- Emacs 配置文件
以下是我整理的 emacs 配置文件,供刚开始玩 emacs 的同学参考.网上有人说:emacs 是神的编辑器,如果能够用到这样的编辑器,那这个人就是神了.从我个人的经验来看,emacs 是一把利器, ...