聲明,本博客從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="width: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', width: 120, align: 'center', sortable: true } ]], columns: [[ { field: 'RoleName', title: '角色名稱', width: 120, align: 'center', sortable: true }, { field: 'RoleSort', title: '默認排序', width: 80, align: 'center', sortable: true }, { field: 'opt', title: '操作', width: 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="width: 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',width:120 },
{ field: 'testValue', title: '<span class="dropitem">測試值</span>', align: 'center', width: 120}]; var url="/Test/Test1Data"; $(document).ready(function () { init(); drag();//綁定datagrid,綁定拖拽 }); function init() { $("#test").datagrid({ url: url, type: "post", datatype: "json", width: 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, width: 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;width: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;width: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#語言的人能夠參考,
轉載請注明原出處!如有索取源代碼請留言,!