本文转自:http://www.cnblogs.com/think8848/archive/2011/07/15/2107828.html
前些天写了一篇有关jqGrid的文章,因为是公司项目的原因一直没有提供源代码,今天又要用jqGrid,顺便做一个示例,以便有需要的人参考。源代码下载
为了使用方便起见,将jqGrid的一些选项放在了_Layout.cshtml中,这样就不用在每一个页面中重复输入了,见代码:
<!DOCTYPE html>
<html>
<head>
<title>@ViewBag.Title</title>
<link href=
"@Url.Content("
~/Content/themes/
base
/site.css
")"
rel=
"Stylesheet"
type=
"text/css"
/>
<link href=
"@Url.Content("
~/Content/themes/
base
/jquery.ui.css
")"
rel=
"Stylesheet"
type=
"text/css"
/>
<link href=
"@Url.Content("
~/Content/themes/
base
/jquery.jqgrid.css
")"
rel=
"Stylesheet"
type=
"text/css"
/>
<script src=
"@Url.Content("
~/Scripts/jquery.js
")"
type=
"text/javascript"
></script>
<script src=
"@Url.Content("
~/Scripts/jquery.ui.js
")"
type=
"text/javascript"
></script>
<script src=
"@Url.Content("
~/Scripts/i18n/grid.locale-cn.js
")"
type=
"text/javascript"
></script>
<script src=
"@Url.Content("
~/Scripts/jquery.jqgrid.js
")"
type=
"text/javascript"
></script>
<script type=
"text/javascript"
>
var
gridContainerId =
'#gridview'
, gridId =
'#list'
;
$(function () {
$.extend($.jgrid.defaults, {
ajaxGridOptions: { contentType:
'application/json; charset=utf-8'
},
datatype:
'json'
,
mtype:
'GET'
,
hidegrid:
false
,
rownumbers:
true
,
rowNum: 10,
rowList: [10, 15, 20],
sortorder:
'asc'
,
viewrecords:
true
,
pager: $(
'#pager'
),
height:
'auto'
,
editfunc: function (id, data) {
return
false
; },
delfunc: function (id, data) {
return
false
; },
cleverjqgridactions:
'clever_jqgrid_actions'
,
colActionsTitle:
'操作'
});
});
function cleverActions(cellvalue, options, rowObject) {
return
'<a href="javascript:void(0)" id="'
+ options.rowId +
'" class="ui-corner-all clever-jqgrid-action clever-jqgrid-edit" style="float: left; margin-left: 5px; padding: 0px;" title="'
+ $.jgrid.nav.edittitle +
'" onclick="actionClick(this,event)" onmouseover="actionMouseover(this,event)" onmouseout="actionMouseout(this,event)" ><span class="ui-icon ui-icon-pencil"></span></a>'
+
'<a href="javascript:void(0)" id="'
+ options.rowId +
'" class="ui-corner-all clever-jqgrid-action clever-jqgrid-del" style="float: left; margin-left: 5px; padding: 0px;" title="'
+ $.jgrid.nav.deltitle +
'" onclick="actionClick(this,event)" onmouseover="actionMouseover(this,event)" onmouseout="actionMouseout(this,event)" ><span class="ui-icon ui-icon-trash"></span></a>'
;
}
function actionMouseover(el, ev) {
$(el).addClass(
'ui-state-hover'
);
if
($.browser.msie) {
ev.cancelBubble =
true
;
}
else
{
ev.stopPropagation();
}
}
function actionMouseout(el, ev) {
$(el).removeClass(
'ui-state-hover'
);
if
($.browser.msie) {
ev.cancelBubble =
true
;
}
else
{
ev.stopPropagation();
}
}
function actionClick(el, ev) {
var
id = $(el).attr(
'id'
);
var
data = $(gridId).jqGrid(
'getRowData'
, id);
if
(data.clever_jqgrid_actions) {
delete data.clever_jqgrid_actions;
}
if
($(el).hasClass(
'clever-jqgrid-edit'
)) {
$(gridId).getGridParam(
'editfunc'
)(id, data);
}
else
if
($(el).hasClass(
'clever-jqgrid-del'
)) {
if
(confirm($.jgrid.del.msg)) {
$(gridId).getGridParam(
'delfunc'
)(id, data);
}
}
if
($.browser.msie) {
ev.cancelBubble =
true
;
}
else
{
ev.stopPropagation();
}
}
</script>
@RenderSection(
"header"
,
false
)
<script type=
"text/javascript"
>
$(function () {
$(window).bind(
'resize'
, function () {
var
width = $(gridContainerId).width();
if
(width ==
null
|| width < 1) {
width = $(gridContainerId).attr(
'offsetWidth'
);
}
width = width - 2;
if
(width > 0 && Math.abs(width - $(gridId).width()) > 5) {
$(gridId).setGridWidth(width);
}
}).trigger(
'resize'
);
});
</script>
</head>
<body>
@RenderBody()
</body>
</html>
|
为了使jqGrid能随着浏览器的缩放而自适应宽度,因此我在视图页面执行完javascript后又为jqGrid指定了resize事件。
在这里值的一提的是,要为jqGrid指定默认选项,需要使用$.jgrid.defaults,方法嘛当然是继承了,这里我把部分默认选项的说明给出来:
//指定请求数据时的ContentType,我使用了json
ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },
//返回数据格式为json
datatype: 'json',
//Http方法为GET
mtype: 'GET',
//隐藏Grid的头
hidegrid: false,
//是否显示行号
rownumbers: true,
//默认显示数据行的个数
rowNum: 10,
//允许显示数据行个数的选项
rowList: [10, 15, 20],
//默认排序策略(升序)
sortorder: 'asc',
//是否显示表脚,即翻页所在的那行
viewrecords: true,
//页脚的容器
pager: $('#pager'),
//Grid高度自动调整
hieght: 'auto',
//这是我自定义的一个功能,后面会提到
editfunc: function (id, data) { return false; },
//自定义功能,同上
delfunc: function (id, data) { return false; },
//自定义功能,同上
cleverjqgridactions: 'clever_jqgrid_actions',
//自定义功能,同上
colActionsTitle: '操作'
一般情况下,在管理系统中,需要尽可能的减少用户的操作步骤,因此,把"编辑","删除"按钮直接放在数据行中,这样用户点一下就可以了,而不需要先选中一行,然后再去点击编辑/删除按钮,因此,使用自定义Formatter的方式,使每行增加一个"编辑","删除"按钮,方法如下:
在colModel中添加一个列:
{ name: $.jgrid.defaults.cleverjqgridactions, width: 80, fixed:
true
, sortable:
false
, resize:
false
, formatter: cleverActions }
|
上文中$.jgrid.defaults.cleverjqgridactions就是这个用途,为这个列提供一个不大可能重复的固定列定,以标示这个列,重点是formatter,为这个选项提供一个方法便是,这个方法的签名如下:
|
function
(cellvalue, options, rowObject){
}
|
cellValue不用理会,因为它本来是指json为这个列提从的值,因为我们这个项不是json提供的,所以它肯定为undefined;
|
options里提供了这个列的定义(colModel中列的定义选项),该字段所在行的主键值(当然,得是你指定了某行为主键),以及jqGrid的id;
|
rowObject是一个数组,为截止目前,所在行的json数据,为啥是截止目前呢?因为当你这一列定义成功后,本列也成为行数据的一员了,在实际应用中,你肯定不希望这列的数据(其实就是你定义的按钮的HTML字符串)作为正式数据传入到业务逻辑里吧,所以使用
delete
方法要删除行数据中的这个字段值,那如何获取这个字段的名称呢?当..当..当,还记得$.jgrid.defaults.cleverjqgridactions吗?当然是使用它了(貌似是一个锉方法哦?)。
|
ok,知道了这些,我们来定义一个自定义的formatter:
|
function
cleverActions(cellvalue, options, rowObject) {
return
'<a href="javascript:void(0)" id="'
+ options.rowId +
'" class="ui-corner-all clever-jqgrid-action clever-jqgrid-edit" style="float: left; margin-left: 5px; padding: 0px;" title="'
+ $.jgrid.nav.edittitle +
'" onclick="actionClick(this,event)" onmouseover="actionMouseover(this,event)" onmouseout="actionMouseout(this,event)" ><span class="ui-icon ui-icon-pencil"></span></a>'
+
'<a href="javascript:void(0)" id="'
+ options.rowId +
'" class="ui-corner-all clever-jqgrid-action clever-jqgrid-del" style="float: left; margin-left: 5px; padding: 0px;" title="'
+ $.jgrid.nav.deltitle +
'" onclick="actionClick(this,event)" onmouseover="actionMouseover(this,event)" onmouseout="actionMouseout(this,event)" ><span class="ui-icon ui-icon-trash"></span></a>'
;
}
|
使用$.jgrid.nav.edittitle和$.grid.nav.deltitle能获取到本地化的
"编辑"
,
"删除"
字符串,这样当用户把鼠标移动上按钮上时,就可以知道这两个按钮是什么用途了,所以将它哥俩的值指定给了a的title。
|
另外,我希望在我点击了
"编辑"
或是
"删除"
按钮时,就不要再触发行选中事件了,因此,我中止了事件冒泡,同样,我也中止了按钮的mouseover和mouseout事件冒泡:
|
function
actionMouseover(el, ev) {
$(el).addClass(
'ui-state-hover'
);
if
($.browser.msie) {
ev.cancelBubble =
true
;
}
else
{
ev.stopPropagation();
}
}
function
actionMouseout(el, ev) {
$(el).removeClass(
'ui-state-hover'
);
if
($.browser.msie) {
ev.cancelBubble =
true
;
}
else
{
ev.stopPropagation();
}
}
function
actionClick(el, ev) {
var
id = $(el).attr(
'id'
);
var
data = $(gridId).jqGrid(
'getRowData'
, id);
if
(data.clever_jqgrid_actions) {
delete
data.clever_jqgrid_actions;
}
if
($(el).hasClass(
'clever-jqgrid-edit'
)) {
$(gridId).getGridParam(
'editfunc'
)(id, data);
}
else
if
($(el).hasClass(
'clever-jqgrid-del'
)) {
if
(confirm($.jgrid.del.msg)) {
$(gridId).getGridParam(
'delfunc'
)(id, data);
}
}
if
($.browser.msie) {
ev.cancelBubble =
true
;
}
else
{
ev.stopPropagation();
}
}
|
代码看到这里,我直是讨厌IE,就是整得和别人不一样。好好的就使用stopPropagation嘛,非得整啥cancelBubble呢?
|
var
id = $(el).attr(
'id'
);
var
data = $(gridId).jqGrid(
'getRowData'
, id);
|
鉴于在点击按钮后再获取行的主键值比较困难,我在生成铵钮时就将行主键值存在a标签的id中了,因此此时取出来,再使用getRowData方法获取该主键所在的行的数据对象,getRowData方法,据官方文档中说,性能不高,使用需谨慎,不要使用在
for
或是
while
中。
|
if
(data.clever_jqgrid_actions) {
delete
data.clever_jqgrid_actions;
}
|
如果行数据包含了按钮HTML文本,则删除数据的这个属性
|
$(gridId).getGridParam(
'editfunc'
)(id, data);
|
使用getGridParam方法调用当点击了编辑按钮时的回调方法。
|
ok,至此,在_Layout.cshtml中的故事就讲完了,接下来我们来看看在实际使用的页面中是如何编码的:
|
@{
ViewBag.Title = "Index";
}
@section header{
<
script
type="text/javascript">
$(function () {
$('#list').jqGrid({
url: '@Url.Action("Index", "User")',
colNames: ['Primary Key', 'User Name', 'Email', $.jgrid.defaults.colActionsTitle],
colModel: [
{ name: 'ID', index: 'ID', width: 1, hidden: true, key: true },
{ name: 'Name', index: 'Name', width: 100, align: 'left' },
{ name: 'Mail', index: 'Mail', width: 100, align: 'left' },
{ name: $.jgrid.defaults.cleverjqgridactions, width: 80, fixed: true, sortable: false, resize: false, formatter: cleverActions }
],
sortname: 'Name',
multiselect: true,
editfunc: function (id, data) {
alert(id);
},
delfunc: function (id, data) {
alert(id);
}
});
});
</
script
>
}
<
div
id="gridview">
<
table
id="list">
</
table
>
<
div
id="pager">
</
div
>
</
div
>
|
有了_Layout.cshtml中的代码,这个页面上的代码就少多了,至少看起来不那么吓人了,照例来讲讲参数吧:
|
//地球人都知道,这是请求数据的url
|
url:
'@Url.Action("Index", "User")'
,
|
//显示用的表头数据,$.jgrid.defaults.colActionsTitle本来的用途是显示"操作"两个字,但是不见得我在每个视图的资源文件中都定义吧,所以还是定义在_Layout.cshtml中,这样使用js的方式调用好可
|
colNames: ['Primary Key', 'User Name', 'Email', $.jgrid.defaults.colActionsTitle],
//定义数据列
|
colModel: [{
|
//列名
|
name: 'ID',
|
//排序时的键
|
index: 'ID',
|
//宽度,应该是px单位
|
width: 1,
|
//隐藏
|
hidden: true,
|
//标示主键列
|
key: true },
{ name: 'Name', index: 'Name', width: 100, align: 'left' },
{ name: 'Mail', index: 'Mail', width: 100, align: 'left' },
{ name: $.jgrid.defaults.cleverjqgridactions, width: 80, fixed: true, sortable: false, resize: false, formatter: cleverActions }
],
//默认使用Name列排序
|
sortname: 'Name',
//是否允许多选,这个选项为true,则前面会加上一个全是checkbox的列,作用不用我多说了吧
|
multiselect: true,
//自定义formatter中编辑按钮的回调方法,id是本行的主键值,data是本行的所有数据
|
editfunc: function (id, data) {
alert(ids);
},
|
//自定义formatter中删除按钮的回调方法
delfunc: function (id, data) {
alert(ids);
}
|
有了这些差不多jqGrid就能很好的工作起来了,但是服务端的数据处理起来也够麻烦的,think8848一向作人厚道,因此专门写了两个助手类,专为jqGrid提供格式化的数据:
|
/// <summary>
/// 分页排序助手类
/// </summary>
public
static
class
DataPagingHelper
{
public
static
IQueryable<T> GetQueryable<T>(
this
IList<T> list,
string
sidx,
string
sord,
int
page,
int
rows)
{
return
GetQueryable<T>(list.AsQueryable<T>(), sidx, sord, page, rows);
}
public
static
IQueryable<T> GetQueryable<T>(
this
IQueryable<T> queriable,
string
sidx,
string
sord,
int
page,
int
rows)
{
var
data = ApplyOrder<T>(queriable, sidx, sord.ToLower() ==
"asc"
?
true
:
false
);
return
data.Skip<T>((page - 1) * rows).Take<T>(rows);
}
private
static
IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> queriable,
string
property,
bool
isASC)
{
PropertyInfo pi =
typeof
(T).GetProperty(property);
ParameterExpression arg = Expression.Parameter(
typeof
(T),
"x"
);
Expression expr = Expression.Property(arg, pi);
Type delegateType =
typeof
(Func<,>).MakeGenericType(
typeof
(T), pi.PropertyType);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
string
methodName = isASC ?
"OrderBy"
:
"OrderByDescending"
;
object
result =
typeof
(Queryable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(
typeof
(T), pi.PropertyType)
.Invoke(
null
,
new
object
[] { queriable, lambda });
return
(IOrderedQueryable<T>)result;
}
}
/// <summary>
/// jqGrid数据处理助手类
/// </summary>
public
static
class
JqGridHelper
{
public
static
JsonResult GetJson<T>(
this
IList<T> datas,
string
sidx,
string
sord,
int
page,
int
rows, JsonRequestBehavior behavior,
params
string
[] fields)
{
return
GetJson<T>(datas.AsQueryable<T>(), sidx, sord, page, rows, behavior, fields);
}
public
static
JsonResult GetJson<T>(
this
IQueryable<T> queriable,
string
sidx,
string
sord,
int
page,
int
rows, JsonRequestBehavior behavior,
params
string
[] fields)
{
var
data = queriable.GetQueryable<T>(sidx, sord, page, rows);
var
json =
new
JsonResult();
json.JsonRequestBehavior = behavior;
if
(rows != 0)
{
var
totalpages = (
decimal
)queriable.Count<T>() / (
decimal
)rows;
totalpages = (totalpages == (
int
)totalpages) ? totalpages : (
int
)totalpages + 1;
var
rowsData = GetJsonData<T>(data, fields);
json.Data =
new
{
page,
records = rows,
total = (
int
)totalpages,
rows = rowsData
};
}
return
json;
}
private
static
object
[] GetJsonData<T>(IQueryable<T> queriable,
params
string
[] fields)
{
var
properties =
typeof
(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
T[] datas = queriable.ToArray<T>();
object
[] result =
new
object
[datas.Length];
if
(fields.Length == 0)
{
fields = Array.ConvertAll<PropertyInfo,
string
>(properties.Where<PropertyInfo>
(x => x.GetCustomAttributes(
typeof
(InternalAttribute),
false
).Length == 0)
.ToArray<PropertyInfo>()
,
delegate
(PropertyInfo p)
{
return
p.Name;
});
}
for
(
int
i = 0; i < datas.Length; i++)
{
object
[] values =
new
object
[fields.Length];
for
(
int
j = 0; j < fields.Length; j++)
{
var
pi = properties.First<PropertyInfo>(x => x.Name == fields[j]);
var
value = pi.GetValue(datas[i],
null
);
values[j] = value !=
null
? value.ToString() :
""
;
}
result[i] =
new
{ id = i, cell = values };
}
return
result;
}
}
/// <summary>
/// 本人项目中使用的,不用深究
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public
class
InternalAttribute : Attribute { }
|
有了这两个助手类,我们再来看提供数据的服务是啥样的:
|
public
class
UserController : Controller
{
//
// GET: /User/
public
ActionResult Index(
string
sidx,
string
sord,
int
page,
int
rows)
{
var
users =
new
List<User>();
users.Add(
new
User() { ID = Guid.NewGuid(), Name =
"think8848"
, Mail =
"think8848@csdn.net"
, Password =
"abcdefg"
});
users.Add(
new
User() { ID = Guid.NewGuid(), Name =
"a"
, Mail =
"a@csdn.net"
, Password =
"abcdefg"
});
users.Add(
new
User() { ID = Guid.NewGuid(), Name =
"b"
, Mail =
"b@csdn.net"
, Password =
"abcdefg"
});
//...
users.Add(
new
User() { ID = Guid.NewGuid(), Name =
"y"
, Mail =
"y@csdn.net"
, Password =
"abcdefg"
});
users.Add(
new
User() { ID = Guid.NewGuid(), Name =
"z"
, Mail =
"z@csdn.net"
, Password =
"abcdefg"
});
return
users.GetJson<User>(sidx, sord, page, rows, JsonRequestBehavior.AllowGet,
new
string
[] {
"ID"
,
"Name"
,
"Mail"
});
}
}
|
User实体定义:
|
public
class
User
{
public
Guid ID {
get
;
set
; }
public
string
Name {
get
;
set
; }
public
string
Password {
get
;
set
; }
public
string
Mail {
get
;
set
; }
}
|
必须得完结了,我的脚被蚊子要抬走了...
|
效果图:
|