用于后台管理的列表数据控件: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()方法做的是将表单中的数 ...
随机推荐
- Android课程---简单的音乐播放器
第一个:用Activity实现 activity_music_play1.xml <?xml version="1.0" encoding="utf-8" ...
- Change the Target Recovery Time of a Database (SQL Server) 间接-checkpoints flushcache flushcache-message
Change the Target Recovery Time of a Database (SQL Server) 间接checkpoints flushcache flushcache-mes ...
- Edge.js:让.NET和Node.js代码比翼齐飞
通过Edge.js项目,你可以在一个进程中同时运行Node.js和.NET代码.在本文中,我将会论述这个项目背后的动机,并描述Edge.js提供的基本机制.随后将探讨一些Edge.js应用场景,它在这 ...
- ASP.NET Core中使用URL重写
ASP.NET Core 1.1 Preview 1 中新增了 URL Rewriting middleware ,终于可以进行 URL 重写了,实际使用体验一下. 首先要将 ASP.NET Core ...
- SQL Agent服务无法启动如何破
问题现象 从阿里云上镜像过来的一台的数据库服务器,SQL Agent服务启动不了,提示服务启动后停止.(原数据库服务器是正常的,怀疑跟镜像有关) 如下是系统日志和SQL Agent的日志 SQLSer ...
- 利用Hexo搭建个人博客-博客初始化篇
上一篇博文 <利用Hexo搭建个人博客-环境搭建篇> 中,我们讲解了利用Hexo搭建个人博客应该要配置哪些环境.相信大家已经迫不及待的想要知道接下来应该要怎么把自己的博客搭起来了,下面,让 ...
- c#设计模式-组合模式
在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象和复合对象 ...
- iOS开发--应用崩溃日志揭秘(二)
场景 4: 吃棒棒糖时闪退! 用户邮件说, “当rage master吃棒棒糖时应用就闪退…” 另一用户说, “我让rage master 吃棒棒糖,没几次应用就闪退了!”崩溃日志如下: Incide ...
- 探讨Js的事件的冒泡阶段
近来看到了一个新的知识点叫Js的事件冒泡,因此决定自己来研究一番. 大家应该都知道,Js中的事件处理分为三个阶段,1:事件的捕获阶段,2:处于目标阶段,3:事件的冒泡阶段.那么什么是事件的捕获和冒泡呢 ...
- angular中的compile和link函数
angular中的compile和link函数 前言 这篇文章,我们将通过一个实例来了解 Angular 的 directives (指令)是如何处理的.Angular 是如何在 HTML 中找到这些 ...