zoukankan      html  css  js  c++  java
  • [原]ASP.NET MVC 3 Razor + jqGrid 示例

    转载请注册作者及出处


    前些天写了一篇有关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,  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',  1, hidden: true, key: true },
                    { name: 'Name', index: 'Name',  100, align: 'left' },
                    { name: 'Mail', index: 'Mail',  100, align: 'left' },
                    { name: $.jgrid.defaults.cleverjqgridactions,  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单位
     1, 
    //隐藏
    hidden: true,
    //标示主键列
    key: true },
                    { name: 'Name', index: 'Name',  100, align: 'left' },
                    { name: 'Mail', index: 'Mail',  100, align: 'left' },
                    { name: $.jgrid.defaults.cleverjqgridactions,  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; }
        }
    
    必须得完结了,我的脚被蚊子要抬走了...
    效果图:
  • 相关阅读:
    关于session
    bootstrap的栅格系统
    js小知识点
    js获取div基础元素
    fixed固定元素
    定时器之延时触发鼠标悬浮事件
    Comparator分组测试
    List去重比较
    点击事件和双击事件
    开机自启动
  • 原文地址:https://www.cnblogs.com/think8848/p/2107828.html
Copyright © 2011-2022 走看看