声明,本博客从csdn搬到cnblogs博客园了,以前的csdn不再更新,朋友们可以到这儿来找我的文章,更多的文章会发表,谢谢关注!
有时候闲的无聊,看到extjs那么肥大,真想把自己的项目改了,最近看到一款轻型的UI感觉不错,但是在网上找了好多教程,但是没有一个是完全是C#asp.net写的
无耐下,自己写了下,感觉效果不错,故拿出来和大学分享一下,希望可以抛砖引玉作用.
由于好多人都只是拷贝代码,故在此全用图片作说明.
图片效果图1
这个界面是上左右下结构
左边是一棵树
右边是一个表格
上部是标题
最下部只是一个空的保留一部分空间
下面开始说下整体结构HTML代码如下
至于HTML代码不想在做多余的解说
下面开始左边的树,在easyUI里面是有树的,但这里没有用,在这里还得感谢Ferry's blogs提供的dTree树,在网上叫无级树,因为它扩展性还是比较好的,在此就用它吧.
在用它之前还是先看下dtree 说明文档,在下载这树JS里面有详细的说明
在上面<head>里面树这样写,不懂可以看下文档这里就不作多解释了.
//<--Tree Begin--> d = new dTree('d'); d.add(0, -1, '个人面板'); function getData(id) { $.ajax({ url: 'TreeSource/GetTreeData.ashx?parentID=' + id, type: 'post', datatype: 'json', success: function (JsonValureturne) { if (JsonValureturne) { //格式化为JSON数据格式 var json = eval("(" + JsonValureturne + ")"); //alert(json.Menu.length); //document.write(returnJsonValue.Menu[0].MenuName); //遍历集合,添加树节点 $.each(json.Menu, function (key, value) { if (id == 0) { d.add(value.ID, value.ParentMenuID, value.MenuName, '', value.MenuName, '', 'img/folder.gif', 'img/folderopen.gif'); } else { d.add(value.ID, value.ParentMenuID, value.MenuName, "javascript:addTab('" + value.MenuName + "','" + value.MenuClickURL + "')", value.MenuName, ''); } //根据模块的ParentID递归绑定数据 getData(value.ID); }) } else { $("#divTree").html(d.toString()); //数据请求完毕,隐藏图片 } } }) } $(getData(0)); //<--Tree End-->
这里我们引用一个后台文件'TreeSource/GetTreeData.ashx?parentID=' + id
意思就是传给后台一个父ID,返回一组json数据
数据库结构这里也贴出来吧,以防有人不理解.
像这样 设计如果还是不懂,请参考dtree文档
下面重点来讲解后台如何来处理及返回数据据的.
<%@ WebHandler Language="C#" class="GetTreeData" %> using System; using System.Web; using System.Data; using System.Collections; using System.Collections.Generic; using System.Web.Script.Serialization; public class GetTreeData : IHttpHandler { public bool IsReusable { get { return false; } } public void ProcessRequest(HttpContext context) { //不让浏览器缓存 // context.Response.Buffer = true; // context.Response.ExpiresAbsolute = DateTime.Now.AddDays(-1); // context.Response.AddHeader("pragma", "no-cache"); // context.Response.AddHeader("cache-control", ""); // context.Response.CacheControl = "no-cache"; context.Response.ContentType = "text/plain"; if (!String.IsNullOrEmpty(GetParentID(context))) { string ParentID = GetParentID(context); DataTable dt = SqlHelper.FillDataTable(String.Format( "SELECT * FROM SunZonTMSMenu WHERE ParentMenuID={0}", ParentID )); IList<Menu> menu = new List<Menu>(); if (dt != null && dt.Rows.Count > 0) { foreach (DataRow dr in dt.Rows) { menu.Add(new Menu() { ID = Int32.Parse(dr["ID"].ToString()), ParentMenuID = Int32.Parse(dr["ParentMenuID"].ToString()), MenuName = dr["MenuName"].ToString(), MenuCode = dr["MenuCode"].ToString(), MenuClickURL = dr["MenuClickURL"].ToString() }); } } if (menu.Count > 0) { context.Response.Write(FormatToJson.ListToJson<Menu>(menu)); } } } public string GetParentID(HttpContext context) { return context.Request["parentID"]; } }
这里使用一个类库SqlHelper.FillDataTable()及IList<Menu> menu = new List<Menu>() meun类
还有一个FormatToJson.ListToJson<T>(T))泛型方法,别吓着了,其它很简单.
先分析一下这里的总体思路.
1)获取前台的父ID
2)通过此ID在数据里查找相应的数据
3)再把返回的数据据填充到自定义的类里面,可能问为什么这样做,因为这样做可以利用反射的方法很好的外理数据,下面会详细的说明
4)把形成的类集合IList<Menu>格式化成json数据并返回给前台
看下怎么查找数据SqlHelper.FillDataTable()方法
就这么简单
下面再看下类Meun
注意了这个类是在VS2010上面写的,每个成员类型必须和数据库一致,
下面关健的一部就是把这个类集合格式化JSON数据,来看下代码
好了,这些基本上完成了转化的方法,
我们来看看前台返回的娄据是什么样的,相信很多人都明白了
如果出现这些数据说明就成功了
这里做下说明吧,Meun就是我们的类名称,数据库里面是什么型的数据这里必须返回什么样的类型,很多json示例都是引号的,这里看到了吧,并不是json数据都用引号,希望这点大家要理解,这也是标准的Json数据形式,为什么我们要把ID作为整形呢,因为我们传给后台的时候用整形或者数据库设计一般都用整形这样可以设主健等等好处,
前台接收数据的时候需要注意的var json = eval("(" + JsonValureturne + ")");
因为我们返回的时候是以字符串形式返回的,必须用eval转化下或者paserjson方法都行的,eval用了双的括号(),这样是把里面的数据才真正意思上的转化为对象
详细请看eval用法,这里就不多说了.
这样一棵树就做好了.
下面开始说右边的内容区
右边是采用jquery easyUI tab面板详情请参考tab文档
在head头部境加代码
//<--Tabs Begin-->
$(function () {
$('#tt').tabs({
tools: [{
iconCls: 'icon-add',
handler: function () {
alert('add');
}
}, {
iconCls: 'icon-save',
handler: function () {
alert('save');
}
}]
});
});
function addTab(tit, link) {
if ($('#tt').tabs('exists', tit)) {
$.messager.alert('提示消息', '窗口已经打开。', 'info');
} else {
$('#tt').tabs('add', {
title: tit,
//href: link,
content: '<iframe scrolling="yes" frameborder="0" src="' + link + '" style="100%;height:98%;"></iframe>',
fit: true,
closable: true
});
}
}
//<--Tabs End-->
这样我们的面板就好了.
下面再看面板里的表是怎么增加的
$('#roleList').datagrid({
title: '',
loadMsg: "数据加载中,请稍后……",
nowrap: false,
striped: true,
collapsible: true,
url: 'ashx/RoleHandler.ashx',
pageList: [10, 15, 20, 25, 30, 40, 50],
pageSize: 15,
sortName: 'RoleSort',
sortOrder: 'asc',
remoteSort: false,
idField: 'RoleCode',
frozenColumns: [[
{ field: 'ck', checkbox: true },
{ title: '角色编码', field: 'RoleCode', 120, align: 'center', sortable: true }
]],
columns: [[
{ field: 'RoleName', title: '角色名称', 120, align: 'center', sortable: true },
{ field: 'RoleSort', title: '默认排序', 80, align: 'center', sortable: true },
{ field: 'opt', title: '操作', 100, align: 'center',
formatter: function (value, rec) {
return '<a href="#" onclick="parent.addTab(\'编辑角色[' + rec.RoleName + ']\', \'Role/Edit.aspx?RoleCode=' + rec.RoleCode + '&RoleName=' + rec.RoleName + '\')"><span style="color:red">编辑</span></a>';
}
}
]],
pagination: true,
rownumbers: true,
onLoadSuccess: function () {
$('.datagrid-toolbar').append($('#txtSearch'));
$('#txtSearch').show();
},
toolbar: [
{
id: 'btnadd',
text: '添加',
iconCls: 'icon-add',
handler: function () {
parent.addTab('添加角色', 'Role/Edit.aspx');
}
}, {
id: 'btncut',
text: '删除',
iconCls: 'icon-cut',
handler: function () {
var codes = getSelections();
if (codes == '') {
$.messager.alert('提示消息', '请选择要删除的数据!', 'info');
} else {
$.messager.confirm('提示消息', '确定要删除所选数据吗?', function (r) {
if (r) {
$('#processWindow').window('open', 'aadasdsads');
$.ajax({
url: 'ashx/RoleHandler.ashx?Codes=' + codes,
type: 'post',
datatype: 'text',
success: function (returnValue) {
if (returnValue) {
$('#processWindow').window('close');
$('#roleList').datagrid('reload');
$('#roleList').datagrid('clearSelections');
}
}
});
}
});
}
}
}, '-',
{
id: 'btnSearch',
text: '搜索',
disabled: false,
iconCls: 'icon-search',
handler: function () {
$('#roleList').datagrid('options').url = 'ashx/RoleHandler.ashx?RoleName=' + escape($('#txtSearch').val());
$('#roleList').datagrid("reload");
}
}
]
}).datagrid("columnMoving");
});
function getSelections() {
var ids = [];
var rows = $('#roleList').datagrid('getSelections');
for (var i = 0; i < rows.length; i++) {
ids.push(rows[i].RoleCode);
}
return ids.join(',');
}
<table id="roleList">
</table>
<div id="processWindow" class="easyui-window" closed="true" modal="true" title="提示消息"
style=" 300px; height: 60px;">
<div id="windowContent" class="general-font">
<img src="jqueryPager/jquery-easyui/themes/gray/images/panel_loading.gif" />
操作进行中,请稍后...
</div>
</div>
<input type="text" id="txtSearch" title="请输入角色名称" style="display: none;" />
下面是后台处理的代码
<%@ WebHandler Language="C#" Class="RoleHandler" %>
using System;
using System.Web;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using System.Web.Script.Serialization;
public class RoleHandler : IHttpHandler
{
#region IHttpHandler Members
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
SqlHelper sqlhelper=new SqlHelper();
if (!String.IsNullOrEmpty(GetRoleCodes(context)))
{
String codes = GetRoleCodes(context);
codes = "'" + codes.Replace(",", "','") + "'";
SqlHelper.ExecuteNonQuery(string.Format("delete from Roles where RoleCode in({0})", codes));
context.Response.Write("true");
}
else
{
int Count;
int pagesiz=GetPageSize(context);
int page=GetPageIndex(context);
DataTable dt = new DataTable();
string sqlWhere = string.Format("RoleName like '%{0}%'", GetRoleName(context));
DataSet ds= SqlHelper.m_QueryPagination("Roles","*",sqlWhere,"RoleSort",pagesiz,page,out Count);
dt = ds.Tables[0];
IList<Roles> list = new List<Roles>();
if (dt != null && dt.Rows.Count > 0)
{
foreach (DataRow dr in dt.Rows)
{
list.Add(new Roles()
{
RoleCode = dr["RoleCode"].ToString(),
RoleName = dr["RoleName"].ToString(),
RoleSort = int.Parse(dr["RoleSort"].ToString())
});
}
}
if (list.Count > 0)
{
dt.Clear();
string data = FormatToJson.ListToJson<Roles>(list, "rows");
data = data.Substring(1);
context.Response.Write(
"{ \"total\":" +Count + "," +data);
}
}
}
public String GetRoleCodes(HttpContext context)
{
return context.Request["Codes"];
}
public Int32 GetPageSize(HttpContext context)
{
try
{
return Int32.Parse(context.Request["rows"].ToString());
}
catch
{
return 10;
}
}
public Int32 GetPageIndex(HttpContext context)
{
try
{
return Int32.Parse(context.Request["page"].ToString());
}
catch
{
return 1;
}
}
public String GetRoleName(HttpContext context)
{
return context.Request["RoleName"];
}
#endregion
}
#region jquery easyUI专用带返回总数分页存储过程 /** USE [Roles] GO -- Object: StoredProcedure [dbo].[AspNetPage] by guyongqing52' Script Date: 12/04/2012 11:38:50 SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER procedure [dbo].[AspNetPage] @tblName varchar(1000), -- 表名 @SelectFieldName varchar(4000), -- 要显示的字段名(不要加select) @strWhere varchar(4000), -- 查询条件(注意: 不要加 where) @OrderFieldName varchar(255), -- 排序索引字段名 @PageSize int , -- 页大小 @PageIndex int = 1, -- 页码 @iRowCount int output, -- 返回记录总数 @OrderType bit = 0 -- 设置排序类型, 0 值则升序,1为降序 AS declare @strSQL varchar(4000) -- 主语句 declare @strTmp varchar(4000) -- 临时变量 declare @strOrder varchar(400) -- 排序类型 declare @strRowCount nvarchar(4000) -- 用于查询记录总数的语句 --去掉排序字段的空格 set @OrderFieldName=ltrim(rtrim(@OrderFieldName)) --如果降序 if @OrderType != 0 begin set @strTmp = '<(select min' set @strOrder = ' order by ' + @OrderFieldName +' desc' end --如果升序 else begin set @strTmp = '>(select max' set @strOrder = ' order by ' + @OrderFieldName +' asc' end --查询主语句 set @strSQL = 'select top ' + str(@PageSize) + @SelectFieldName+' from ' + @tblName + ' where ' + @OrderFieldName + @strTmp + '(' + right(@OrderFieldName,len(@OrderFieldName)-charindex('.',@OrderFieldName)) + ') from (select top ' + str((@PageIndex-1)*@PageSize) + @OrderFieldName + ' from ' + @tblName + @strOrder + ') as tblTmp)' + @strOrder --如果条件不为空 if @strWhere != '' set @strSQL = 'select top ' + str(@PageSize) + @SelectFieldName+' from ' + @tblName + ' where ' + @OrderFieldName + @strTmp + '(' + right(@OrderFieldName,len(@OrderFieldName)-charindex('.',@OrderFieldName)) + ') from (select top ' + str((@PageIndex-1)*@PageSize) + @OrderFieldName + ' from ' + @tblName + ' where ' + @strWhere + ' ' + @strOrder + ') as tblTmp) and ' + @strWhere + ' ' + @strOrder --如果页面为1 if @PageIndex = 1 begin set @strTmp = '' if @strWhere != '' set @strTmp = ' where ' + @strWhere set @strSQL = 'select top ' + str(@PageSize) + @SelectFieldName+' from ' + @tblName + @strTmp + ' ' + @strOrder end --执行语句 exec(@strSQL) --如果条件不为空 if @strWhere!='' begin set @strRowCount = 'select @iRowCount=count(*) from ' + @tblName+' where '+@strWhere end else begin set @strRowCount = 'select @iRowCount=count(*) from ' + @tblName end --执行语句 exec sp_executesql @strRowCount,N'@iRowCount int out',@iRowCount out **/ #endregion
这样基本上就完成了,看下再这几个效果,说不定会有意外的收获.
这个图说明easyUi gridview本身就有鼠标经过每行里自动改变背景色的功能,
这个图有点类似extjs的分页功能,说明它具有分页大小可以根据下列表形式选择,很不错的功能.
这个图片说明列宽拖动也是自带的,哈哈,真不错哦再看下面
这个图充分说明了我们前面固定前面的两例保持不变
后面的项可以滚动,这项有时候很实用.其实还有很多不错的功能,比如说列宽自适应,数据可以格式化,列可以编缉,可以增加下列选择项列等等,这里不详细介绍了
下面我们看看网上很多站点使用的很炫列支持拖动,
easyui gridview本身是不支持列拖动的,但是UI里面却有可支持拖动的方法,详情请参见文档
网上有文章这样写的,
<script type="text/javascript">
var cols = [{ field: 'testName', title: '<span class="dropitem">测试名</span>', align: 'center',120 },
{ field: 'testValue', title: '<span class="dropitem">测试值</span>', align: 'center', 120}];
var url="/Test/Test1Data";
$(document).ready(function () {
init();
drag();//绑定datagrid,绑定拖拽
});
function init() {
$("#test").datagrid({
url: url,
type: "post",
datatype: "json",
600,
height: 280,
loadMsg: "数据加载中,请稍后...",
nowrap: true,
rownumbers: false,
pagination: true,
singleSelect: true,
columns: [cols],
//bind数据成功重新设置拖动对象
onLoadSuccess: function (data) {
drag();
}
});
}
//拖动drag和drop都是datagrid的头的datagrid-cell
function drag() {
$('.datagrid-header-inner .datagrid-cell').draggable({
revert: true,
proxy: 'clone'
}).droppable({
accept: '.datagrid-header-inner .datagrid-cell',
onDrop: function (e, source) {
//取得拖动源的html值
var src = $(e.currentTarget.innerHTML).html();
//取得拖动目标的html值
var sou = $(source.innerHTML).html();
var tempcolsrc;//拖动后源和目标列交换
var tempcolsou;
var tempcols=[];
for (var i = 0; i < cols.length; i++) {
if (cols[i].title == sou) {
tempcolsrc = cols[i];//循环读一遍列把源和目标列都记下来
}
else if (cols[i].title == src) {
tempcolsou = cols[i];
}
}
for (var i = 0; i < cols.length; i++) {
//再循环一遍,把源和目标的列对换
var col = {
field: cols[i].field,
title: cols[i].title,
align: cols[i].align,
cols[i].width
};
if (cols[i].title == sou) {
col = tempcolsou;
}
else if (cols[i].title == src) {
col = tempcolsrc;
}
tempcols.push(col);
}
cols = tempcols;
//1秒后执行重绑定datagrid操作。可能是revert需要时间,这边如果没有做延时就直接重绑 就会出错。
//我目前的水平就想到这个笨办法,各位如果有好的想法建议可以提出来讨论下。
timeid = setTimeout("init()", 1000);
}
});
}
</script>
<div id="test"></div>
感觉这个人写的很不错,思路很清淅,但是这个方法我没有采用,因为不宜扩展,这里还得谢谢上面提供的思路.
下面看扩展方法
$(function () {
//-以下是扩展移动方法
$.extend($.fn.datagrid.methods, {
columnMoving: function (jq) {
return jq.each(function () {
var target = this;
var cells = $(this).datagrid('getPanel').find('div.datagrid-header td[field]');
cells.draggable({
revert: true,
cursor: 'pointer',
edge: 5,
proxy: function (source) {
var height = $(source).height();
var width = $(source).width() - 20;
var bordercolor = $(source).css("background-color");
var p = $('<div class="tree-node-proxy tree-dnd-no" style="position:absolute;border:1px solid ' + bordercolor + '"/>').appendTo('body');
p.css({ "background-color": bordercolor });
p.html($(source).text());
p.height(height);
p.width(width);
p.hide();
return p;
},
onBeforeDrag: function (e) {
e.data.startLeft = $(this).offset().left;
e.data.startTop = $(this).offset().top;
},
onStartDrag: function () {
$(this).draggable('proxy').css({
left: -10000,
top: -10000
});
},
onDrag: function (e) {
$(this).draggable('proxy').show().css({
left: e.pageX - 30,
top: e.pageY - 5
});
return false;
}
}).droppable({
accept: 'td[field]',
onDragOver: function (e, source) {
$(source).draggable('proxy').removeClass('tree-dnd-no').addClass('tree-dnd-yes');
$(this).css('border-left', '1px solid #ff0000');
var left = $(this).offset().left -5;
var top1 = $(this).offset().top - 10;
var top2 = $(this).offset().top +24;
var pgb1 = $('<div id="guang1" style="position:absolute; index-z:888888;background:#fff url(img/guangbiao1.gif) no-repeat 0 0;10px;height:8px"></div>').appendTo('body');
var pgb2 = $('<div id="guang2" style="position:absolute; index-z:888888;background:#fff url(img/guangbiao2.gif) no-repeat 0 0;12px;height:12px"></div>').appendTo('body');
pgb1.css({ "top": top1, "left": left });
pgb2.css({ "top": top2, "left": left });
},
onDragLeave: function (e, source) {
$(source).draggable('proxy').removeClass('tree-dnd-yes').addClass('tree-dnd-no');
$(this).css('border-left', 0);
$("body #guang1").hide();
$("body #guang2").hide();
},
onDrop: function (e, source) {
$(this).css('border-left', 0);
$("body #guang1").hide();
$("body #guang2").hide();
var fromField = $(source).attr('field');
var toField = $(this).attr('field');
setTimeout(function () {
moveField(fromField, toField);
$(target).datagrid();
$(target).datagrid('columnMoving');
}, 0);
}
});
// move field to another location
function moveField(from, to) {
var columns = $(target).datagrid('options').columns;
var cc = columns[0];
var c = _remove(from);
if (c) {
_insert(to, c);
}
function _remove(field) {
for (var i = 0; i < cc.length; i++) {
if (cc[i].field == field) {
var c = cc[i];
cc.splice(i, 1);
return c;
}
}
return null;
}
function _insert(field, c) {
var newcc = [];
for (var i = 0; i < cc.length; i++) {
if (cc[i].field == field) {
newcc.push(c);
}
newcc.push(cc[i]);
}
columns[0] = newcc;
}
}
});
}
});
调用的时候只要在后面加上$('#roleList').datagrid({...}).datagrid("columnMoving");这句就行了,怎么样,简单吧,还有听过几位网友的说,把拖动的时候上下指示箭头做成闪动的效果更好些,这些细节这里不作多解释,好了就写到这吧,祝使用asp.net C#语言的人能够参考,
转载请注明原出处!如有索取源代码请留言,!