.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控制器基类

  View Code

控制器DefaultController

  View Code

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

Index视图:

  View Code

Create视图:

  View Code

Update视图:

  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代码如下:

  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点,一是自身对这块掌握得不好,二是公司都是后端开发人员,就按照这种最简单的方式进行封装。

  View Code

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

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


本文转自邹琼俊博客园博客,原文链接:http://www.cnblogs.com/jiekzou/p/7430043.html,如需转载请自行联系原作者

相关文章
|
3月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
41 0
|
1月前
|
开发框架 前端开发 .NET
进入ASP .net mvc的世界
进入ASP .net mvc的世界
29 0
|
1月前
mvc.net分页查询案例——mvc-paper.css
mvc.net分页查询案例——mvc-paper.css
5 0
|
1月前
|
开发框架 前端开发 .NET
C# .NET面试系列六:ASP.NET MVC
<h2>ASP.NET MVC #### 1. MVC 中的 TempData\ViewBag\ViewData 区别? 在ASP.NET MVC中,TempData、ViewBag 和 ViewData 都是用于在控制器和视图之间传递数据的机制,但它们有一些区别。 <b>TempData:</b> 1、生命周期 ```c# TempData 的生命周期是短暂的,数据只在当前请求和下一次请求之间有效。一旦数据被读取,它就会被标记为已读,下一次请求时就会被清除。 ``` 2、用途 ```c# 主要用于在两个动作之间传递数据,例如在一个动作中设置 TempData,然后在重定向到另
95 5
|
2月前
|
JavaScript 前端开发 Java
MooTools、Backbone、Sammy、Cappuccino、Knockout、JavaScript MVC、Google Web Toolkit、Google Closure、Ember、Batman 以及 Ext JS。
MooTools、Backbone、Sammy、Cappuccino、Knockout、JavaScript MVC、Google Web Toolkit、Google Closure、Ember、Batman 和 Ext JS 都是 JavaScript 框架,用于开发 Web 应用程序。它们分别提供了不同的功能和特性,以帮助开发者更高效地构建和维护 Web 应用程序。
17 2
|
3月前
|
XML 前端开发 定位技术
C#(NET Core3.1 MVC)生成站点地图(sitemap.xml)
C#(NET Core3.1 MVC)生成站点地图(sitemap.xml)
25 0
|
3月前
|
前端开发
.net core mvc获取IP地址和IP所在地(其实是百度的)
.net core mvc获取IP地址和IP所在地(其实是百度的)
123 0
|
4月前
|
JSON JavaScript 前端开发
全面的.NET微信网页开发之JS-SDK使用步骤、配置信息和接口请求签名生成详解
全面的.NET微信网页开发之JS-SDK使用步骤、配置信息和接口请求签名生成详解
|
5月前
|
存储 SQL 前端开发
自定义MVC增删改查(CRUD)---超详细讲解
自定义MVC增删改查(CRUD)---超详细讲解
42 0
|
5月前
|
开发框架 自然语言处理 前端开发
基于ASP.NET MVC开发的、开源的个人博客系统
基于ASP.NET MVC开发的、开源的个人博客系统
52 0