easyui与mvc的结合
easyui与mvc的结合
上一篇文章发布后,自己又仔细读了数遍,感觉一是文笔太差,二是描述逻辑比较混乱,客观原因是涉及到东西其实蛮多的,那三个步骤不可能在一篇短短的文章中就可以描述清楚。此篇笔者将尽量更加详尽一些。另外需要说明一点的是,本文默认读者:
熟悉ASP.NET MVC Razor语法 熟悉javascript 实体框架Web应用不像winform应用,要想让用户得到更流畅更舒适的体验,方法之一就是模拟winform的窗口操作,使用户在浏览器中也能像桌面一样舒服。在界面框架方面我们有大家最熟悉的jquery ui,有Ext等等,经过一系列的筛选,我们最终决定使用easyui,文档教程例子都比较全面的一个js ui框架。首先我们来看看用到的js文件
< script src ="@Url.Content(" ~/Scripts/jquery-1.7.2.min.js")" type ="text/javascript" ></ script > jquery主文件
< script src ="@Url.Content(" ~/Scripts/jquery.easyui.min.js")" type ="text/javascript" ></ script > easy ui主文件
< script src ="@Url.Content(" ~/Scripts/jquery.validate.min.js")" type ="text/javascript" ></ script > 校验组件
< script src ="@Url.Content(" ~/Scripts/jquery.form.js")" type ="text/javascript" ></ script > 表单组件
< script src ="@Url.Content(" ~/Scripts/easyui-lang-zh_CN.js")" type ="text/javascript" ></ script > easyui的中文化
< script src ="@Url.Content(" ~/Scripts/messages_cn.js")" type ="text/javascript" ></ script > 校验组件的中文化
我们把它添加到mvc的Shared/_Layout.cshtml中。这样我们的项目所有Layout=null的视图都拥有了easyui支持。
在MVC3中,当你右键添加一个控制器时,向导会让你选择:
其中模版我们选择使用实体框架并生成相关actions与views,Model选择你实体框架中对应的表名(类名),DataContext选择上下文类
Views引擎选择Razor,高级选项里的两个勾都去掉,因为我们不需要引用内置的脚本库,也不需要选择layout(不选择layout,MVC默认该view使用Shared/_Layout.cshtml,也就是刚才我们添加js文件link的那个文件)。
确认上一篇中你下载的t4模版放进了它应该存在的地方(最好备份一下原始的),当你点击Add时,vs会自动在Controllers下面添加相应的控制器,在views文件夹下添加Create、Edit、Delete、Details、Index五个文件。下面我们一一查看他们的内容:
控制器中,action已经自动帮你添加完毕
private BsmisEntities db = new BsmisEntities();
//
// GET: /User/
public ViewResult Index()
{
return View();
}
//
// GET: /User/Create
public ActionResult Create()
{
return View();
}
//
// POST: /User/Create
[HttpPost]
public ActionResult Create(T_User t_user)
{
JsonResult result = new JsonResult();
result.Data = true ;
try
{
if (t_user.Enable == null )
t_user.Enable = 0 ;
db.T_User.AddObject(t_user);
db.SaveChanges();
}
catch (Exception ee)
{
result.Data = ee.Message;
}
return result;
}
//
// GET: /User/Edit/5
[OutputCache(Location = OutputCacheLocation.None)]
public ActionResult Edit( int id)
{
T_User t_user = db.T_User.Single(t => t.UserID == id);
ViewBag.DepartmentID = new SelectList(db.T_DepartmentInfo, " DepartmentID " , " Code " , t_user.DepartmentID);
return View(t_user);
}
//
// POST: /User/Edit/5
[HttpPost]
[OutputCache(Location = OutputCacheLocation.None)]
public ActionResult Edit(T_User t_user)
{
JsonResult result = new JsonResult();
result.Data = true ;
try
{
db.T_User.Attach(t_user);
db.ObjectStateManager.ChangeObjectState(t_user, EntityState.Modified);
db.SaveChanges();
}
catch (Exception ee)
{
result.Data = ee.Message;
}
return result;
}
//
// POST: /User/Delete/5
[HttpPost, ActionName( " Delete " )]
public ActionResult DeleteConfirmed( int id)
{
JsonResult json=new JsonResult();
json.Data=true;
try
{
T_User t_user = db.T_User.Single(t => t.UserID == id);
db.T_User.DeleteObject(t_user);
db.SaveChanges();
}
catch(Exception ee)
{
json.Data=ee.Message;
}
return json;
}
/// <summary>
/// 数据显示、分页信息
/// </summary>
/// <param name="page"></param>
/// <param name="rows"></param>
/// <returns></returns>
public JsonResult List( int page, int rows)
{
var q = from u in db.T_User
join d in db.T_DepartmentInfo on u.DepartmentID equals d.DepartmentID
orderby u.UserID
select new
{
UserID = u.UserID,
UserName = u.UserName,
Address = u.Address,
Birth = u.Birth,
DepartmentID = u.DepartmentID,
DepartmentName = d.Name,
Enable = u.Enable,
Gendar = u.Gendar,
IDCardNumber = u.IDCardNumber,
LastAccessIP = u.LastAccessIP,
LastAccessTime = u.LastAccessTime,
LogonTimes = u.LogonTimes,
Password = u.Password,
PostCode = u.PostCode,
RealName = u.RealName,
Tel = u.Tel,
Province = u.Province,
City = u.City,
Area = u.Area
};
var result = q.Skip((page - 1 ) * rows).Take(rows).ToList();
Dictionary < string , object > json = new Dictionary< string , object > ();
json.Add( " total " , q.ToList().Count);
json.Add( " rows " , result);
return Json(json, JsonRequestBehavior.AllowGet);
}
这些action分别对应create、delete、edit、index视图(detail我们一般情况下不需要它,所以我的模版里没有写对应的生成代码)你可以比较一下它与原生的模版生成的代码之间的区别。后期我们还会在控制器里添加一些譬如检查名称是否重名之类的action
[OutputCache(Location = OutputCacheLocation.None)]
public JsonResult CheckRealNameExist( string RealName, int UserID)
{
JsonResult result = new JsonResult();
result.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
result.Data = false ;
try
{
if (UserID == 0 )
{
if (db.T_User.Any(p => p.RealName == RealName))
{
return result;
}
}
else
{
if (db.T_User.Any(p => ((p.UserID != UserID) && (p.RealName == RealName))))
{
return result;
}
}
}
catch (Exception)
{
return result;
}
result.Data = true ;
return result;
}
返回值一般都是jsonresult。这样的话,当你在浏览器中访问http://localhost:1233/User/CheckRealNameExist?RealName=张三&UserID=0时 你会获得一个true或false值。是不是跟webservice有点异曲同工?
同样,在Views文件夹中生成了Create、Edit、Details、Delete、Index五个文件,其中Details与Delete我们不需要,因为我们想使用更友好的异步删除(用户单击delete后,页面不刷新,成功后浏览器下方滑出提示,3秒后关闭,失败滑出失败信息,不自动关闭 /利用easyui中的messager组件)。以下是Index中的js:
// 删除
function del() {
var id = getselectedRow();
if (id != undefined) {
$.messager.confirm( '确认', '确定删除?', function (r) {
if (r) {
var url = 'User/Delete/' + id;
$.post(url, function () {
}).success( function () {
$.messager.show({
title: '提示' ,
msg: '删除成功' ,
timeout: 3000 ,
showType: 'slide'
});
$( '#dg').datagrid('reload' );
})
.error( function () {
$.messager.alert( '错误', '删除发生错误' );
});
}
});
}
}
我们把Details与Delete删除后只剩下Index、Create、Edit三个文件,这三个文件之间的关系是,Index中包含添加、编辑按钮,点击后使用js将对应的actionresult加载到div中,以实现弹窗新建,编辑的效果。
// 新建
function c_dlg() {
var url = 'User/Create' ;
$( '#c_dlg' ).show();
$( '#c_dlg').load(url, function () {
$( this ).dialog({
title: '添加' ,
buttons: [{
text: '提交' ,
iconCls: 'icon-ok' ,
handler: function () {
$( '#c_form' ).submit();
}
}, {
text: '取消' ,
handler: function () {
$( '#c_dlg').dialog('close' );
}
}]
});
});
}
// 编辑框
function e_dlg() {
var id = getselectedRow();
if (id != undefined) {
var url = 'User/Edit/' + id;
$( '#e_dlg' ).show();
$( '#e_dlg').load(url, function () {
$( this ).dialog({
title: '编辑' ,
buttons: [{
text: '提交' ,
iconCls: 'icon-ok' ,
handler: function () {
$( '#e_form' ).submit();
}
}, {
text: '取消' ,
handler: function () {
$( '#e_dlg').dialog('close' );
}
}]
});
});
}
}
这里面的c_dlg与e_dlg是index页面的两个Div节点:
< div id ="c_dlg" style ="400px;height:520px;display: none" ></ div >
< div id ="e_dlg" style ="400px;height:520px;display: none" ></ div >
以上的代码完成将控制器中的action返回的页面内容动态加载到div中,并以弹窗的特效显示在当前(Index)页面中。效果如图:
我们来看看Create\Edit视图的内容,首先是js
<script type="text/javascript">
$( function () {
$( '#c_Department' )测试数据botree({
url: '@Url.Action("GetComboTreeJson","Department")'
});
$( '#c_City' )测试数据bobox();
$( '#c_Area' )测试数据bobox();
$( '#c_Province')测试数据bobox({ url:'CityDic/List/ID/0' ,
onSelect: function (record) {
$( '#c_City')测试数据bobox('reload', 'CityDic/List/ID/' + record.ID)测试数据bobox('clear' );
$( '#c_Area')测试数据bobox('clear' );
}
});
$( '#c_City' )测试数据bobox({
onSelect: function (record) {
$( '#c_Area')测试数据bobox('reload', 'CityDic/List/ID/' + record.ID)测试数据bobox('clear' );
}
});
$( '#c_Birth').datebox().datebox('setValue', '@now' );
$( "#c_form" ).validate({
rules: {
UserName: {
required: true ,
remote:
{
url: 'User/CheckNameExist' ,
type: "get" ,
dataType: "json" ,
data: {
Name: function () { return $('#c_UserName' ).val(); },
UserID: function () { return 0 ; }
}
}
},
RealName: {
required: true ,
remote: {
url: 'User/CheckRealNameExist' ,
type: "get" ,
dataType: "json" ,
data: {
RealName: function () { return $('#c_RealName' ).val(); },
UserID: function () { return 0 ; }
}
}
}
},
messages: {
UserName: {
remote: '名称重复'
},
RealName: { remote: '名称重复' }
},
submitHandler: function (form) {
ajaxAdd();
}
});
});
</script>
这部分js将本页面的控件初始化为对应的下拉框或日期选取框等等,Html为
@using (Html.BeginForm("Create", "User", FormMethod.Post, new { id = "c_form" }))
{
< fieldset >
< table class ="editForm" >
< tr >
< td >
@Html.LabelFor(model => model.UserName, "用户名:")
</ td >
< td >
< input id ="c_UserName" name ="UserName" style =" 160px;" required ="true" />< span style ="color: red" >
* </ span >
</ td >
</ tr >
< tr >
< td >
@Html.LabelFor(model => model.DepartmentID, "组织机构:")
</ td >
< td >
< input id ="c_Department" name ="DepartmentID" style =" 160px;" required ="true" />< span style ="color: red" >
* </ span >
</ td >
</ tr >
< tr >
< td >
@Html.LabelFor(model => model.Password, "密码:")
</ td >
< td >
@Html.PasswordFor(model => model.Password, new { @class = "{required:true,minlength:5}" }) < span style ="color: red" >
* </ span >
</ td >
</ tr >
< tr >
< td >
< label for ="confirm_password" >
确认密码 </ label >
</ td >
< td >
< input id ="confirm_password" name ="confirm_password" type ="password" class ="{required:true,minlength:5,equalTo:'#Password'}" />< span style ="color: red" >
* </ span >
</ td >
</ tr >
< tr >
< td >
@Html.LabelFor(model => model.RealName, "真实姓名:")
</ td >
< td >
@Html.TextBoxFor(model => model.RealName, new { @id="c_RealName",@class = "{required:true}" }) < span style ="color: red" >
* </ span >
</ td >
</ tr >
< tr >
< td >
@Html.LabelFor(model => model.Gendar, "性别:")
</ td >
< td >
@Html.RadioButtonFor(model => model.Gendar, "男", new { @id = "radio1", @name = "Gendar", @checked = "checked" })
< label for ="radio1" >
男 </ label >
@Html.RadioButtonFor(model => model.Gendar, "女", new { @id = "radio2", @name = "Gendar" })
< label for ="radio2" >
女 </ label >
</ td >
</ tr >
< tr >
< td >
@Html.LabelFor(model => model.Birth, "出生日期:")
</ td >
< td >
< input id ="c_Birth" required ="true" name ="Birth" />
</ td >
</ tr >
< tr >
< td >
@Html.LabelFor(model => model.IDCardNumber, "身份证号码:")
</ td >
< td >
@Html.EditorFor(model => model.IDCardNumber)
</ td >
</ tr >
< tr >
< td >
@Html.LabelFor(model => model.Province, "省份:")
</ td >
< td >
< input name ="Province" valuefield ="Name" textfield ="Name" panelheight ="auto" id ="c_Province" style =" 150px" >
</ td >
</ tr >
< tr >
< td >
@Html.LabelFor(model => model.City, "市:")
</ td >
< td >
< input name ="City" valuefield ="Name" textfield ="Name" panelheight ="auto" id ="c_City" style ="150px" >
</ td >
</ tr >
< tr >
< td >
@Html.LabelFor(model => model.Area, "区/县:")
</ td >
< td >
< input name ="Area" valuefield ="Name" textfield ="Name" panelheight ="auto" id ="c_Area" style =" 150px" >
</ td >
</ tr >
< tr >
< td >
@Html.LabelFor(model => model.PostCode, "邮政编码:")
</ td >
< td >
@Html.EditorFor(model => model.PostCode)
</ td >
</ tr >
< tr >
< td >
@Html.LabelFor(model => model.Address, "地址:")
</ td >
< td >
@Html.EditorFor(model => model.Address)
</ td >
</ tr >
< tr >
< td >
@Html.LabelFor(model => model.Tel, "电话:")
</ td >
< td >
@Html.EditorFor(model => model.Tel)
</ td >
</ tr >
< tr >
< td >
@Html.LabelFor(model => model.Enable, "启用:")
</ td >
< td >
@Html.CheckBoxForBool(model=>model.Enable,true,true)
</ td >
</ tr >
</ table >
</ fieldset >
}
编辑视图中也类似如此。当单击保存按钮后,执行
$('#c_form').submit();
这里我们的客户端校验在这里:
$("#c_form" ).validate({
rules: {
UserName: {
required: true ,
remote:
{
url: 'User/CheckNameExist' ,
type: "get" ,
dataType: "json" ,
data: {
Name: function () { return $('#c_UserName' ).val(); },
UserID: function () { return 0 ; }
}
}
},
RealName: {
required: true ,
remote: {
url: 'User/CheckRealNameExist' ,
type: "get" ,
dataType: "json" ,
data: {
RealName: function () { return $('#c_RealName' ).val(); },
UserID: function () { return 0 ; }
}
}
}
},
messages: {
UserName: {
remote: '名称重复'
},
RealName: { remote: '名称重复' }
},
submitHandler: function (form) {
ajaxAdd();
}
});
submitHandler方法提供校验前要做的事情:ajaxAdd()
// 异步新建提交
function ajaxAdd() {
$( '#c_form' ).ajaxSubmit({
url: 'User/Create' ,
beforeSubmit: function () {
if ($('#c_form').form('validate') != true ) {
return false ;
}
if ($("#c_form").valid() != true ) {
return false ;
}
return true ;
},
success: function (data) {
if (data == true ) {
$( '#c_dlg').dialog('close' );
$( '#dg').datagrid('reload' );
$.messager.show({
title: '提示' ,
msg: '保存成功' ,
timeout: 2000 ,
showType: 'slide'
});
} else {
$.messager.show({
title: '提示' ,
msg: '保存失败:' + data,
timeout: 2000 ,
showType: 'slide'
});
}
}
});
return false ;
}
异步提交成功后获取data,如果是true说明成功了,关闭“对话框”,刷新表格,弹出提示。失败的话将data弹出(一般是失败原因,由controller中的action返回)。下面是Index中的表格:
< table id ="dg" class ="easyui-datagrid"
toolbar ="#toolbar"
rownumbers ="true" fitColumns ="true" singleSelect ="true" pagination ="true" fit ="true" >
< thead >
< tr >
< th field ="DepartmentName" width ="80" >
部门
</ th >
< th field ="UserName" width ="100" >
用户名
</ th >
< th field ="RealName" width ="100" >
真实姓名
</ th >
< th field ="Gendar" width ="30" >
性别
</ th >
< th field ="Birth" width ="70" formatter ="formatDate" >
生日
</ th >
< th field ="Tel" width ="50" >
电话
</ th >
< th field ="LogonTimes" width ="50" >
登陆次数
</ th >
< th field ="LastAccessIP" width ="120" >
最后访问IP
</ th >
< th field ="LastAccessTime" width ="50" >
最后访问时间
</ th >
< th field ="Enable" width ="50" formatter ="formatBool" >
状态
</ th >
</ tr >
</ thead >
</ table >
< div id ="toolbar" >
@if (userid != 0 && AuthMgr.HasAuth(userid, "add", 5))
{
< a href ="#" class ="easyui-linkbutton" iconCls ="icon-add" plain ="true" onclick ="c_dlg();" > 添加 </ a >
}
@if (userid != 0 && AuthMgr.HasAuth(userid, "edit", 5))
{
< a href ="#" class ="easyui-linkbutton" iconCls ="icon-edit" plain ="true" onclick ="e_dlg()" > 编辑 </ a >
}
</ div >
其中@if是用来判断权限,如果当前登陆用户拥有add权限,那么就显示“添加“按钮。
今天先写到这。
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息