zoukankan      html  css  js  c++  java
  • .Net MVC&&datatables.js&&bootstrap做一个界面的CRUD有多简单

        我们在项目开发中,做得最多的可能就是CRUD,那么我们如何在ASP.NET MVC中来做CRUD呢?如果说只是单纯实现功能,那自然是再简单不过了,可是我们要考虑如何来做得比较好维护比较好扩展,如何做得比较漂亮。做开发要有工匠精神,不要只求完成开发任务,那样的话,永远停留在只是简单的写业务逻辑代码水平,我们要做有追求的程序员。本来这么简单的东西,我真是懒得写,但是看到即便是一些工作了好些年的人,做东西也是只管实现功能,啥都不管,还有些界面css样式要么就硬编要么就毫无规则的在页面中进行穿插,遇到要设置间距甚至直接写多个 ,我觉得还是要写出来给那些人看下。硬编的前提是只有你这一个界面使用。

        我们先来看下我们要实现的效果,功能需要:新增、修改、删除、查询、分页、排序、导出excel、打印、上传图片、支持表单验证,优雅的实现有多简单?非常简单。

    需要用到哪些UI组件?我都是基于bootstrap这种扁平化响应式风格的,jquery.dataTables.js、toastr.js、bootstrapValidator.js、bootstrap-confirmation.js、printThis.js

    由于是演示用,所以控制器中直接调用了EF上下文操作,重点是看前端部分的渲染和交互,不要重复你的代码!不要重复你的代码!不要重复你的代码!重要的事情说三遍!为什么没有用mvc自带的模型验证?答:太傻逼!1、样式改起来操蛋;2、每次要点击提交表单才促发验证。

    这里表数据量少,是直接一次性加载,然后内存中分页的,如果表数据量多,那么就要用服务器分页,同样很简单。修改下配置项,如下所示:然后控制器中对应的方法稍微修改下即可。

    options.bServerSide = true;,
    options.fnServerParams = function (aoData) { //查询条件 aoData.push( { "name": "LogName", "value": $("#LogName").val() } ); };

     BaseController控制器基类

        [PublicAuthorize]
        public class BaseController : Controller
        {
            HomeService _HomeService = new HomeService();
            #region 字段
    
            /// <summary>
            /// 新增
            /// </summary>
            protected string CText = "新增";
            /// <summary>
            /// 读取
            /// </summary>
            protected string RText = "读取";
            /// <summary>
            /// 更新
            /// </summary>
            protected string UText = "更新";
            /// <summary>
            /// 删除
            /// </summary>
            protected string DText = "删除";
            /// <summary>
            /// 数据有误!
            /// </summary>
            protected string VoidText = "数据有误!";
    
            #endregion
    
            #region 属性
            /// <summary>
            /// 获取点击的菜单ID
            /// </summary>
            public string MenuId { get { return Request.QueryString["MenuId"]; } }
            /// <summary>
            /// 自动构建页面标题导航
            /// </summary>
            public MvcHtmlString HeadString
            {
                get { return new MvcHtmlString(_HomeService.GetHead(int.Parse(MenuId))); }
            } 
            /// <summary>
            /// 构造非菜单页的界面导航标题
            /// </summary>
            /// <param name="title">页面标题</param>
            public void CreateSubPageHead(string title)
            {
                ViewBag.HeadString = HeadString;
                ViewBag.MenuId = MenuId;
                ViewBag.SubHeadString = title; 
            }
            #endregion
            [HttpGet]
            public virtual ActionResult Index()
            {
                if (!string.IsNullOrEmpty(MenuId))
                {
                    ViewBag.MenuId = MenuId;
                    ViewBag.HeadString = HeadString;
                }
                return View();
            }
            /// <summary>
            /// 操作成功
            /// </summary>
            /// <param name="message">提示文本</param>
            /// <returns></returns>
            protected virtual AjaxResult SuccessTip(string message)
            {
                return new AjaxResult { state = ResultType.success.ToString(), message = message };
            }
            /// <summary>
            /// 操作失败
            /// </summary>
            /// <param name="message">提示文本</param>
            /// <returns></returns>
            protected virtual AjaxResult ErrorTip(string message)
            {
                return new AjaxResult { state = ResultType.error.ToString(), message = message };
            }
        }
    View Code

    控制器DefaultController

        public class DefaultController : BaseController
        {
            private MyContext db = new MyContext();
            /// <summary>
            /// 客户列表
            /// </summary>
            /// <param name="filter"></param>
            /// <returns></returns>
            [HttpPost]
            public JsonResult List(Customer filter)
            {
                //filter.PageSize = int.MaxValue;
                IQueryable<Customer> dataSource = db.Customers;
    
                if (!string.IsNullOrEmpty(filter.Name))
                {
                    dataSource = dataSource.Where(x => x.Name == filter.Name).OrderBy(x => x.CreateTime);
                }
    
                List<Customer> queryData = dataSource.ToList();
    
                var data = queryData.Select(u => new
                {
                    ID = u.Id,
                    Name = u.Name,
                    CreateTime = u.CreateTime.ToDateStr(),
                    Address = u.Address
                });
    
                //构造成Json的格式传递
                var result = new { iTotalRecords = queryData.Count, iTotalDisplayRecords = 10, data = data };
                return Json(result, JsonRequestBehavior.AllowGet);
            }
            #region CRUD
            [HttpGet]
            public ActionResult Create()
            {
                return View();
            }
            [HttpPost]
            public JsonResult Create([Bind(Include = "Name,Address,CreateTime,Msg,HeadsUrl")] Customer _Customer)
            {
                AjaxResult _AjaxResult = null;
                if (ModelState.IsValid)
                {
                    db.Customers.Add(_Customer);
                    _AjaxResult = db.SaveChanges() > 0 ? SuccessTip(string.Format("{0}成功!", CText)) : ErrorTip(string.Format("{0}失败!", CText)); ;
                }
                else
                {
                    _AjaxResult = ErrorTip(VoidText);
                }
                return Json(_AjaxResult, JsonRequestBehavior.AllowGet);
            }
    
            [HttpGet]
            public ActionResult Update(int Id)
            {
                var model = db.Customers.Where(x => x.Id == Id).FirstOrDefault();
                return View(model);
            }
            [HttpPost]
            public JsonResult Update([Bind(Include = "Id,Name,Address,CreateTime,Msg,HeadsUrl")] Customer _Customer)
            {
                AjaxResult _AjaxResult = null;
                if (ModelState.IsValid)
                {
                    db.Entry(_Customer).State = EntityState.Modified;
                    _AjaxResult = db.SaveChanges() > 0 ? SuccessTip(string.Format("{0}成功!", UText)) : ErrorTip(string.Format("{0}失败!", UText));
                }
                else
                {
                    _AjaxResult = ErrorTip(VoidText);
                }
                return Json(_AjaxResult, JsonRequestBehavior.AllowGet);
            }
            [HttpPost]
            public JsonResult Delete(int Id)
            {
                var model = db.Customers.Where(x => x.Id == Id).FirstOrDefault();
                db.Customers.Remove(model);
                AjaxResult _AjaxResult = db.SaveChanges() > 0 ? SuccessTip(string.Format("{0}成功!", DText)) : ErrorTip(string.Format("{0}失败!", DText));
    
                return Json(_AjaxResult, JsonRequestBehavior.AllowGet);
            }
            [HttpPost]
            public JsonResult DeleteList(List<int> ids)
            {
                var list = db.Customers.Where(x => ids.Contains(x.Id)).ToList();
                db.Customers.RemoveRange(list);
                AjaxResult _AjaxResult = db.SaveChanges() > 0 ? SuccessTip(string.Format("{0}成功!", DText)) : ErrorTip(string.Format("{0}失败!", DText));
    
                return Json(_AjaxResult, JsonRequestBehavior.AllowGet);
            }
    
            #endregion
    
            #region File handle
            /// <summary>
            /// 导出Excel
            /// </summary>
            /// <returns></returns>
            public FileResult ExportExcel()
            {
                string excelPath = Server.MapPath("~/Excel/用户列表.xls");
                GenerateExcel genExcel = new GenerateExcel();
                genExcel.SheetList.Add(new UserListSheet(db.Customers.ToList(), "用户列表"));
                genExcel.ExportExcel(excelPath);
                return File(excelPath, "application/ms-excel", "用户列表.xls");
            }
            /// <summary>
            /// 上传文件
            /// </summary>
            /// <returns></returns>
            public JsonResult ExportFile()
            {
                HttpPostedFileBase file = Request.Files["txt_file"];
                uploadFile _uploadFile = new uploadFile();
    
                if (file != null)
                {
                    string str = DateTime.Now.ToString("yyyyMMddhhMMss");
                    var fileFullName =string.Format("{0}{1}_{2}",Request.MapPath("~/Upload/"),str ,file.FileName);
                    try
                    {
                        file.SaveAs(fileFullName);
                        _uploadFile.state = 1;
                    }
                    catch
                    {
                        _uploadFile.state = 0;
                    }
                    finally
                    {
                        _uploadFile.name = str+"_"+file.FileName;
                        _uploadFile.fullName = fileFullName;
                    }
                }
                else
                {
                    _uploadFile.state = 0;
                }
                return Json(_uploadFile, JsonRequestBehavior.AllowGet);
            }
            /// <summary>
            /// 删除文件
            /// </summary>
            /// <returns></returns>
            [HttpPost]
            public JsonResult DeleteFile(string key)
            {
                var fileFullName = Path.Combine(Request.MapPath("~/Upload"), key);
                int state = 0;
                try
                {
                    state = FileHelper.DeleteFile(fileFullName) ? 1 : 0;
                    //var model = db.Customers.Where(x => x.HeadsUrl == key).FirstOrDefault();
                    //if(model!=null)
                    //{
                    //    db.Customers.Remove(model);
                    //}
                }
                catch
                {
                    state = 0;
                }
                return Json(state, JsonRequestBehavior.AllowGet);
            } 
    
            #endregion
        }
    View Code

    视图页面,razor、css、js都分离,不要放到一个文件中。

    Index视图:

    @model List<Secom.Smp.Data.Models.Customer>
    @{
        ViewBag.Title = "用户列表";
        ViewBag.ParentTitle = "系统管理";
        Layout = "~/Views/Shared/_Page.cshtml";
    }
    <style type="text/css">
        .divModal {
            width: 700px;
        }
    </style>
    <div class="page-content-body">
        <div class="row">
            <div class="col-md-12">
                <!-- BEGIN EXAMPLE TABLE PORTLET-->
                    <div class="portlet-title">
                        <div class="caption font-dark">
                            <i class="icon-settings font-dark"></i>
                            <span class="caption-subject bold uppercase">用户列表</span>
                        </div>
                        <div class="actions">
                           
                        </div>
                    </div>
                    <div class="portlet-body">
                        <div class="table-toolbar">
                            <div class="row">
                                <div class="col-md-6">
                                    <div class="btn-group">
                                        <button id="btnAdd" class="btn sbold green" onclick="DataTablesObj.doCreateModal('/Admin/Default/Create')" data-toggle="modal">添加用户<i class="fa fa-plus"></i></button>
                                        <button id="btnDeleteList" title="确定要删除吗?" class="btn sbold btn-danger deleteBtn" data-toggle="confirmation" data-placement="right" data-btn-ok-label="继续" data-btn-ok-icon="icon-like" data-btn-ok-class="btn-success" data-btn-cancel-label="取消"
                                                data-btn-cancel-icon="icon-close" data-btn-cancel-class="btn-danger">
                                            批量删除
                                            <i class="fa fa-minus"></i>
                                        </button>
                                    </div>
                                </div>
                                <div class="col-md-6">
                                    <div class="btn-group pull-right">
                                        <button class="btn green  btn-outline dropdown-toggle" data-toggle="dropdown">
                                            操作
                                            <i class="fa fa-angle-down"></i>
                                        </button>
                                        <ul class="dropdown-menu pull-right">
                                            <li>
                                                <a href="/Admin/Default/ExportExcel" target='_blank' class="fa fa-file-excel-o"><span style="margin-left:10px;"> 导出Excel </span></a>
                                            </li>
                                            <li>
                                                <a href="#" class="fa fa-file-excel-o" id="printView"><span style="margin-left:10px;"> 打印预览</span></a>
                                            </li>
                                        </ul>
                                    </div>
    
                                </div>
                            </div>
                        </div>
                        <table class="table table-striped table-bordered table-hover table-checkable order-column" id="table_local"></table>
                    </div>
                <!--模态弹窗-->
                <div class="modal fade" id="defaultModal" tabindex="-1" role="dialog" aria-labelledby="defaultModalLabel" aria-hidden="true">
                    <div class="modal-dialog divModal" role="document">
                        <div class="modal-content">
                        </div>
                    </div>
                </div>
                <!-- END EXAMPLE TABLE PORTLET-->
            </div>       
            </div>
    </div>
    @section scripts
    {
    <script src="@Html.ScriptsPath("lib/printThis.js")"></script>
    }
    View Code

    Create视图:

    @model Secom.Smp.Data.Models.Customer
    @{
        ViewBag.Title = "Create";
        Layout = "~/Views/Shared/_Form.cshtml";
    }
    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="defaultModalLabel">添加用户</h4>
    </div>
    @using (Html.BeginForm("Create", "Default", new { area = "Admin" }, FormMethod.Post, new { @id = "defaultForm" }))
                {
        <div class="modal-body">
            <div class="row">
                <div class="col-md-5">
                        <div class="form-group">
                            @Html.LabelFor(x => x.HeadsUrl,new { @class = "control-label" }):
                            <input type="file" id="txt_file" name="txt_file" class="file-loading" accept="image/*" />
                            @Html.HiddenFor(x=>x.HeadsUrl,new { @id = "hidFileUrl" })
                        </div>
                    </div>
                <div class="col-md-7">
                    <div class="form-group">
                        @Html.LabelFor(x => x.Name, new { @class = "control-label" }):
                        @Html.TextBoxFor(x => x.Name, new { @id = "Name", @placeholder = "请输入用户名", @class = "form-control" })
                    </div>
                    <div class="form-group">
                        @Html.LabelFor(x => x.Address, new { @class = "control-label" }):
                        @Html.TextBoxFor(x => x.Address, new { @id = "Address", @placeholder = "请输入地址", @class = "form-control" })
                    </div>
                    <div class="form-group">
                        @Html.LabelFor(x => x.CreateTime):
                        <div class="input-group input-medium date date-picker">
                            @Html.TextBoxFor(x => x.CreateTime, new { @class = "form-control", @readonly = true })
                            <span class="input-group-btn">
                                <button class="btn default" type="button">
                                    <i class="fa fa-calendar"></i>
                                </button>
                            </span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
            <button type="submit" class="btn sbold green">提交</button>
        </div>
    }
    @section scripts
    {
    
    }
    View Code

    Update视图:

    @model Secom.Smp.Data.Models.Customer
    @{
        ViewBag.Title = "Update";
        Layout = "~/Views/Shared/_Form.cshtml";
    }
    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="defaultModalLabel">修改用户</h4>
    </div>
    
        @using (Html.BeginForm("Update", "Default", new { area = "Admin" }, FormMethod.Post, new { @id = "updateForm" }))
        {
            @Html.HiddenFor(x=>x.Id)
            <div class="modal-body">
                <div class="row">
                    <div class="col-md-5">
                        <div class="form-group">
                            @Html.LabelFor(x => x.HeadsUrl, new { @class = "control-label" }):
                            <input type="file" id="txt_file" name="txt_file" class="file-loading" accept="image/*" />
                            @Html.HiddenFor(x => x.HeadsUrl, new { @id = "hidFileUrl" })
                        </div>
                    </div>
                    <div class="col-md-7">
                        <div class="form-group">
                            @Html.LabelFor(x => x.Name, new { @class = "control-label" }):
                            @Html.TextBoxFor(x => x.Name, new { @id = "Name", @placeholder = "请输入用户名", @class = "form-control" })
                        </div>
                        <div class="form-group">
                            @Html.LabelFor(x => x.Address, new { @class = "control-label" }):
                            @Html.TextBoxFor(x => x.Address, new { @id = "Address", @placeholder = "请输入地址", @class = "form-control" })
                        </div>
                        <div class="form-group">
                            @Html.LabelFor(x => x.CreateTime):
                            <div class="input-group input-medium date date-picker">
                                @Html.TextBoxFor(model => model.CreateTime,
               new { @type = "date", @class = "form-control", @readonly = true, @Value = Model.CreateTime.ToDateStr(),@id= "CreateTime" })
                                <span class="input-group-btn">
                                    <button class="btn default" type="button">
                                        <i class="fa fa-calendar"></i>
                                    </button>
                                </span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
                <button type="submit" class="btn sbold green">提交</button>
            </div>
        }
     @section scripts
    {
    
    }
    View Code

    _Form模板页视图

    <!DOCTYPE html>
    <html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>@ViewBag.Title</title>
    </head>
    <body>
        @RenderBody()
        @RenderSection("scripts", required: false)
                @Html.AutoLoadPageJs()
    </body>
    </html>

    看下这个自定义的扩展方法AutoLoadPageJs方法,其实就是模拟mvc的路由寻址方式去找指定目录下面的js

            /// <summary>
            /// 根据mvc路由自动加载js文件(如果不存在则不加载)
            /// </summary>
            /// <param name="helper"></param>
            /// <returns></returns>
            public static MvcHtmlString AutoLoadPageJs(this HtmlHelper helper)
            {
                var areas = helper.ViewContext.RouteData.DataTokens["area"];
                var action = helper.ViewContext.RouteData.Values["action"];
                var controller = helper.ViewContext.RouteData.Values["controller"];
                string url = areas == null ? string.Format("views/{0}/{1}", controller, action) : string.Format("views/areas/{2}/{0}/{1}", controller, action, areas);
    
                return LoadJsString(helper,url);
            }
            /// <summary>
            /// 构造js加载的html字符串
            /// </summary>
            /// <param name="helper"></param>
            /// <param name="url">js文件路径</param>
            /// <returns></returns>
            public static MvcHtmlString LoadJsString(HtmlHelper helper, string url)
            {
                var jsBuilder = new StringBuilder();
                string jsLocation = "/content/release-js/";
    #if DEBUG
                jsLocation = "/content/js/";
    #endif
                string jsFullUrl = Path.Combine(jsLocation, url + ".js");
    
                if (File.Exists(helper.ViewContext.HttpContext.Server.MapPath(jsFullUrl)))
                {
                    jsBuilder.AppendFormat("<script src="{0}"></script>", jsFullUrl);
                }
                return new MvcHtmlString(jsBuilder.ToString());
            }

    我们看下View对应的js文件

    index.js

    $(function () {
        //-------------初始化datatable
        var obj = DataTablesObj;
        obj.showReadBtn = false;//显示详情按钮
        obj.showDeleteBtn = true;//显示删除按钮
        obj.showUpdateBtn = true;//显示更新按钮
    
        obj.updateUrl = "/Admin/Default/Update";
        obj.deleteUrl = "/Admin/Default/Delete";
        obj.batchDeleteUrl = "/Admin/Default/DeleteList";//批量删除路径
    
        obj.options.columns = [{ title: "", "visible": false, "data": "ID" },
               obj.checboxFied,
               { "data": "Name", title: "用户名称" },
               { "data": "Address", title: "用户地址" },
               { "data": "CreateTime", title: "创建时间" },
               obj.opratorFiled
        ];
        obj.options.searching = true;
        obj.options.sAjaxSource = "/Admin/Default/List"; //数据源地址
        obj.init(obj.options);
        //表单验证配置项
        FormValidatorObj.options.fields = {
            Name: {
                message: '用户名验证失败',
                validators: {
                    notEmpty: {
                        message: '用户名不能为空'
                    }
                }
            },
            Address: {
                validators: {
                    notEmpty: {
                        message: '地址不能为空'
                    }
                }
            }
        };
        //打印预览
        $("#printView").on("click", function () {
            $("#table_local").printThis({
                debug: false,// 调试模式下打印文本的渲染状态
                importCSS: true,
                importStyle: true,
                printContainer: true,
                //loadCSS: "/Content/bootstrap.css",
                pageTitle: "用户列表",
                removeInline: false,
                printDelay: 333,
                header: null,
                formValues: true,
                header: "<h1>用户列表</h1>",
                footer: null
            });
        })
    })

    create.js

    $(function () {
        DatetimepickerObj.init('CreateTime');//(控件ID)
        //--------------表单验证
        FormValidatorObj.init("defaultForm","defaultModal","table_local"); //(表单id,[modal容器Id],[datable容器ID])
        //初始化编辑界面的数据
        //--------------添加界面中的上传控件
        FileInputObj.init(undefined,"txt_file", "hidFileUrl", "/Admin/Default/ExportFile",true);  //配置项,控件ID,存储文件路径的控件ID,上传路径,是否新增页面
    });

    update.js

    $(function () {
        DatetimepickerObj.init('CreateTime');//(控件ID)
        //--------------表单验证
        FormValidatorObj.init("updateForm","defaultModal","table_local"); //(表单id,[modal容器Id],[datable容器ID])
        //初始化编辑界面的数据
        //([配置项],控件ID,存储文件路径的控件ID,图片路径,上传路径,删除路径)
        FileInputObj.initUpdateImg(undefined,"txt_file", "hidFileUrl", "/Admin/Default/ExportFile", "/Admin/Default/DeleteFile");
    })

    看上去比较多的界面功能,你看下,代码就这么点,而且各自职责很清晰。对datatables.js组件进行二次封装,base-Datatable.js代码如下:

    // ajax加载调试用
    //# sourceURL=base-Datatable.js
    
    //DataTables表格组件扩展对象--created by zouqj 2017-7-03
    var DataTablesObj = (function () {
        //------------------------------静态全局属性-------------------------------------
        var infoStr = "总共 <span class='pagesStyle'>(_PAGES_) </span>页,显示 _START_ -- _END_ ,共<span class='recordsStyle'> (_TOTAL_)</span> 条";
    
        var lengthMenuStr = '每页显示:<select class="form-control input-xsmall">' + '<option value="5">5</option>' + '<option value="10">10</option>' + '<option value="20">20</option>' + '<option value="30">30</option>'
             + '<option value="50">50</option>' + '<option value="100">100</option>' + '<option value="150">150</option>' + '<option value="200">200</option>' + '<option value="250">250</option>' + '<option value="500">500</option>';
    
        this.table_local = "table_local"; //table ID
        this.chkAllColl = "chkAllColl"; //全选按钮ID
        this.modalId = "defaultModal"; //模态窗体ID
        this.batchDeleteBtn = "btnDeleteList"; //批量删除按钮ID
        this.deleteBtn = "btnDelete"; //删除按钮ID
        this.autoIncrement={'title': '序号', 'data': null, 'bSortable': false,'render': function (data, type, full, meta) {return meta.row + 1 + meta.settings._iDisplayStart;}}; // 序号
        //操作列
        this.opratorFiled = {
            "data": "ID", orderable: false, title: "操作", "render": function (data, type, row, meta) { //自定义列
                var re = "<div class='operatorDiv'></i>";
                if (DataTablesObj.showReadBtn) {
                    var temp = DataTablesObj.detailModal == undefined ? data : data + ",'" + DataTablesObj.detailModal+"'";
                    re += "<a class='' type='button' data-toggle='dropdown' aria-expanded='false' onclick="DataTablesObj.doReadModal(" + temp + ")">详情</a>";
                }
                if (DataTablesObj.showUpdateBtn) {
                    var temp = DataTablesObj.updateModal == undefined ? data : data + ",'" + DataTablesObj.updateModal + "'";
                    re += "<a class='' type='button' onclick='DataTablesObj.doUpdateModal(" + temp + ")'>编辑</a>";
                }
                if (DataTablesObj.showDeleteBtn) {
                    re += "<a class='' title='确定要删除吗?' data-toggle='confirmation' data-placement='left' data-btn-ok-label='继续' data-btn-ok-icon='icon-like' data-btn-ok-class='btn-success toastrBtn' data-btn-cancel-label='取消' data-btn-cancel-icon='icon-close' data-btn-cancel-class='btn-danger' type='button' onclick='DataTablesObj.doDelete(this," + data + ")'>删除</a>";
                }
                re += "</div>";
                return re;
            }
        };
        //复选框列
        this.checboxFied = {
            "data": "ID", title: "<input type='checkbox' id='chkAllColl' onclick='DataTablesObj.selectAll()'/>", orderable: false,
            "render": function (data, type, row, meta) {
                return "<input id='cbx" + data + "' name='chkItem' type='checkbox' onclick='DataTablesObj.controlSelectAll(" + data + ")' class='cbx' value='" + data + "'/>  ";
            }
        };
        //------------------------------变化部分的属性-------------------------------------
        this.batchDeleteUrl = "";//批量删除路径
        this.deleteUrl = ""; //单条记录删除路径
        this.showReadBtn = true;//默认不显示详情按钮
        this.showDeleteBtn = false;//默认不显示删除按钮
        this.showUpdateBtn = false;//默认显示更新按钮
        this.readUrl = ""; //单条记录读取路径
        this.updateUrl = "";//更新界面URL地址
        this.detailModal = undefined; //详情页面的modalId
        this.updateModal = undefined;//修改页面的modalId
    
        //------------------------------事件、方法-------------------------------------
        document.onkeydown = function (event) {
            var e = event || window.event || arguments.callee.caller.arguments[0];
            if (e && e.keyCode == 27) { // 按 Esc 
                //要做的事情
            }
            if (e && e.keyCode == 13) { // enter 键
                //要做的事情
                DataTablesObj.reloadList(DataTablesObj.table_local);
            }
        };
        ////对行单击添加监听事件
        //$('#table_local tbody').on('click', 'tr', function () {
        //    var tr = $(this).closest('tr');
        //    var checkbox = tr.find('td:first-child input:checkbox')[0];
        //    checkbox.checked = !checkbox.checked;
        //});
        //获Ggridview中所有的复选框 sName: Gridview 的ID  
        this.getCheckbox = function (sName) {
            var aryCheckbox = new Array();
            var tb = document.getElementById(sName);
            if (tb == null)
                return;
            var objs = tb.getElementsByClassName("cbx");
            for (var i = 0; i < objs.length; i++) {
                if (objs[i].type == 'checkbox')
                    aryCheckbox.push(objs[i]);
            }
            return aryCheckbox;
        };
    
        //监听每一行的复选框,控制全选、反选按钮  
        this.controlSelectAll = function (i) {
            var tblName, cbkAll; //Gridview ID ,全选框ID  
            var tblName = DataTablesObj.table_local;
            var cbkAll = DataTablesObj.chkAllColl;
            var id = "#cbx" + i;
            //点击复选框选中行
            //if ($(id)[0].checked == true) {
            //    $(id).parent().parent().addClass('selected');
            //    $(id).parent().parent().siblings().removeClass('selected');
            //} else {
            //    $(id).parent().parent().siblings().removeClass('selected');
            //    $(id).parent().parent().removeClass('selected');
            //}
            var chks = DataTablesObj.getCheckbox(tblName);
            var count = 0;
            for (var i = 0; i < chks.length; i++) {
                if (chks[i].checked == true) {
                    count++;
                }
            }
            if (count < chks.length) {
                document.getElementById(cbkAll).checked = false;
            }
            else {
                document.getElementById(cbkAll).checked = true;
            }
        };
        //全选反选
        this.selectAll = function () {
            var isChecked = $("#" + DataTablesObj.chkAllColl)[0].checked;
            $("input[name='chkItem']").prop("checked", isChecked);
        };
        //查询刷新([datatable ID])
        this.reloadList = function (id) {
            var tableId = id == undefined ? DataTablesObj.table_local : id;
            var tables = $('#' + tableId).dataTable().api();//获取DataTables的Api,详见 http://www.datatables.net/reference/api/
            tables.ajax.reload();
        };
        //****************************************************************************************************************
    
        //新增记录(异步请求界面url,[modal ID],[回调函数])
        this.doCreateModal = function (url, modalId, func) {
            var modalId = modalId == undefined ? DataTablesObj.modalId : modalId;
            $('#' + modalId).modal({ show: true, backdrop: 'static', remote: url });
            if (func != undefined) {
                func();
            }
        };
        //详细记录(主键ID,[modal ID],[异步请求界面url])
        this.doReadModal = function (id, modalId, readUrl) {
            var modalId = modalId == undefined ? DataTablesObj.modalId : modalId;
            var url = readUrl == undefined ? DataTablesObj.readUrl : readUrl;
            $('#' + DataTablesObj.modalId).modal({ show: true, backdrop: 'static', remote:url  + "?id=" + id });
        }
        //编辑记录(主键ID,[异步请求界面url],[modal ID])
        this.doUpdateModal = function (id, modalId,updateUrl) {
            var modalId = modalId == undefined ? DataTablesObj.modalId : modalId;
            var url = updateUrl == undefined ? DataTablesObj.updateUrl : updateUrl;
            $('#' + modalId).modal({ show: true, backdrop: 'static', remote: url + "?id=" + id });
        };
        //删除选中记录(批量删除url地址)
        this.doDeleteList = function (url) {
            var table = $('#' + DataTablesObj.table_local).dataTable();
            var nTrs = table.fnGetNodes();//fnGetNodes获取表格所有行,nTrs[i]表示第i行tr对象
            var row;
            var strdid = '';
            var selectCounts = 0;
            for (var i = 0; i < nTrs.length; i++) {
                if ($(nTrs[i])[0].cells[0].children[0].checked) {
                    row = table.fnGetData(nTrs[i]);//fnGetData获取一行的数据        
                    selectCounts++;
                    strdid += "" + row.ID + ",";
                }
            }
            strdid = strdid.substring(0, strdid.length - 1);
            var ids = strdid.split(",");
            if (selectCounts < 1) {
                toastr.warning("请先选择数据行!");
                return false;
            }
            $.ajax({
                type: 'POST',
                url: url,
                data: { 'ids': ids },
                dataType: 'json',
                success: function (result) {
                    toastr.success(result.message);
                    DataTablesObj.reloadList(DataTablesObj.table_local);
                }
            });
        }
        //删除单条记录(控件id,主键id)
        this.doDelete = function (btn, id) {
            $(btn).on('confirmed.bs.confirmation', function () {
                $.post(DataTablesObj.deleteUrl, { Id: id }, function (result) {
                    toastr.success(result.message);
                    DataTablesObj.reloadList(DataTablesObj.table_local);
                });
            });
            $(btn).confirmation('show');
        };
        this.options = {
            bProcessing: true,
            //"scrollY": table_h1,// 340,// 
            "scrollX": false,
            //"scrollCollapse": "true",
            //dom:"",//'ftr<"bottom"lip>',//<"clear">
            "bServerSide": false, //指定从服务器端获取数据
            sServerMethod: "POST",
            sAjaxSource: "",
            autoWidth: false,
            fnServerParams: null,
            columns: null,
            paging: true,//分页
            ordering: true,//是否启用排序
            searching: false,//搜索
            language: {
                "sProcessing": "处理中...",
                lengthMenu: lengthMenuStr,//左上角的分页大小显示。
                search: '<span class="label label-success">搜索:</span>',//右上角的搜索文本,可以写html标签
    
                //paginate: {//分页的样式内容。
                //    previous: "上一页",
                //    next: "下一页",
                //    first: "",
                //    last: ""
                //},
                "paginate": {
                    "previous": "Prev",
                    "next": "Next",
                    "last": "Last",
                    "first": "First"
                },
    
                zeroRecords: "",//table tbody内容为空时,tbody的内容。--暂无记录
                //下面三者构成了总体的左下角的内容。
                info: infoStr,//左下角的信息显示,大写的词为关键字。初始_MAX_ 条
                infoEmpty: "0条记录",//筛选为空时左下角的显示。
                infoFiltered: ""//筛选之后的左下角筛选提示,
            },
            pagingType: "bootstrap_full_number"//分页样式的类型 "full_numbers"//
        };
        //监听批量删除按钮事件(控件ID,url删除地址)
        this.listenerDeleteEvent = function (ctrlId, url) {
            $('#' + ctrlId).on('confirmed.bs.confirmation', function () {
                DataTablesObj.doDeleteList(url);
            }).on("click", function () {
                $('#' + ctrlId).confirmation('show');
            });
        }
        //控件初始化(配置项,[table容器ID],[删除对象])
        this.init = function (options, tableId,obj) {
            var tableId = tableId == undefined ? DataTablesObj.table_local : tableId;
            var opts = options == undefined ? DataTablesObj.options : options;
            $('#' + tableId).dataTable(opts);
            if (obj == undefined) {
                DataTablesObj.listenerDeleteEvent(DataTablesObj.batchDeleteBtn, DataTablesObj.batchDeleteUrl);
            } else {
                obj.listenerDeleteEvent(obj.batchDeleteBtn, obj.batchDeleteUrl);
            }      
            delete options.aoColumns;//同一个页面多处使用时,要先删除此对象,具体原因不明
        };
        //批量初始化(options配置数组,tables id数组)-不添加监听事件
        this.initList = function (opts, ids) {
            if (opts!=undefined &&opts!=null &&opts.length>0&& ids != undefined&& ids!=null && ids.length > 0) {
                var length = ids.length;
                for (var i = 0; i < length; i++) {
                    $('#' + ids[i]).dataTable(opts[i]);
                }
            }
        }
        return this;
    }).call({});
    View Code

    我们进行二次封装的UI组件对象,他们的options属性,是复杂属性,也就是类似与引用类型,要使用深拷贝然后再去修改,否则修改的是引用而不是副本。我这里没有去使用clone,而是直接在options对象上进行赋值了,那是因为我赋值的那些属性每个引用页面都会去再赋值一遍,而js是运行在客户端的,也就是说每个客户的电脑上面都会有一份完整的js文件副本,这和运行在服务器端的C#语言是不一样的。其实使用  var options = clone(DataTablesObj.options);再去给options赋值是标准做法,但是会失去一部分性能。我的js水平太菜,所以封装得不是特别好,但是至少页面干净、方便维护。

    js方法上面的注释,我也是按照自定义的风格进行注释,参数用()括起来,可选参数就用[],这些东西都可以当成约定或者规范,目的就是为了让所有的开发人员写的代码像一个人写的。本来我想把方法的参数都封装成一个对象的,只是之前觉得参数个数少,就没有那样去封装了,参数用对象的好处就是可以无序,而且更易扩展,所有这些进行二次封装的UI组件,文件命名我都加了前缀base-,其实里面的对象命名我是加的后缀Obj,你也可以根据自己的爱好设定,比如说公司名称简写作为前缀,但是一定确定了,就要团队成员遵守约定。

    日期组件同样进行封装base-Datetimepicker.js,这里的打印我暂时就没有去进行封装了。在js中通常使用原型链的方式来实现继承,我这里没有使用,原因2点,一是自身对这块掌握得不好,二是公司都是后端开发人员,就按照这种最简单的方式进行封装。

    //ajax加载调试用
    //# sourceURL=base-Datetimepicker.js
    
    //Datetimepicker日期组件扩展对象--created by zouqj 2017-7-13
    var DatetimepickerObj = (function () {
        this.options = {
            language: 'zh-CN',//显示中文
            format: 'yyyy-mm-dd',//显示格式
            minView: "month",//设置只显示到月份
            initialDate: new Date(),//初始化当前日期
            autoclose: true,//选中自动关闭
            todayBtn: true//显示今日按钮
        };
        this.init= function (ctrlId) {
            $("#" + ctrlId).datetimepicker(DatetimepickerObj.options);
        }
        //(开始日期控件,结束日期控件)
        this.initStartEnd = function (startCtrl, endCtrl) {
            var startCtrl = $("#" + startCtrl);
            var endCtrl = $("#" + endCtrl);
            startCtrl.datetimepicker({
                format: 'yyyy-mm-dd',
                minView: 'month',
                language: 'zh-CN',
                autoclose: true,
                startDate: new Date()
            }).on("click", function () {
                startCtrl.datetimepicker("setEndDate", endCtrl.val())
            });
            endCtrl.datetimepicker({
                format: 'yyyy-mm-dd',
                minView: 'month',
                language: 'zh-CN',
                autoclose: true,
                startDate: new Date()
            }).on("click", function () {
                endCtrl.datetimepicker("setStartDate", startCtrl.val())
            });
        }
        return this;
    }).call({});
       
    View Code

    那么其实我们界面上真正自己要写的就3个View,3个js,一个控制器提供对应的方法调用,其它的不管是C#还是js都去进行封装,css样式通通按照规范写成皮肤文件。项目中可以有一个皮肤css,一个布局css,一个自定义css。

    所以说.net做东西就是这么简单,看似复杂的功能界面,一下子就搞定了,只要把东西都封装好了,做一个这样的功能最多大半天就搞定,仔细看下js总共就写几十行左右,还算上了复制粘贴修改下的,哪里需要去经常加班?加班应该是php程序员和java程序员的专利,做不加班的.net程序员~

  • 相关阅读:
    HDU 3081 Marriage Match II
    HDU 4292 Food
    HDU 4322 Candy
    HDU 4183 Pahom on Water
    POJ 1966 Cable TV Network
    HDU 3605 Escape
    HDU 3338 Kakuro Extension
    HDU 3572 Task Schedule
    HDU 3998 Sequence
    Burning Midnight Oil
  • 原文地址:https://www.cnblogs.com/jiekzou/p/7430043.html
Copyright © 2011-2022 走看看