一步一步asp.net ajax類別Tree生成
更新時(shí)間:2012年05月03日 02:34:33 作者:
關(guān)于類別樹(shù)的多級(jí)是一個(gè)剛接觸ajax和多級(jí)類別很頭痛的問(wèn)題,針對(duì)那種商品種類繁多,級(jí)別層次多更是麻煩的問(wèn)題,去年剛學(xué)asp.net,實(shí)驗(yàn)室的同學(xué)曾經(jīng)這樣做過(guò),遞歸sql,現(xiàn)在看了驚心動(dòng)魄

雖然實(shí)現(xiàn)了類別多級(jí)的問(wèn)題這樣帶來(lái)的后果確實(shí)無(wú)窮無(wú)盡的.............
遞歸查詢,和雙循環(huán)嵌套的執(zhí)行sql語(yǔ)句沒(méi)什么區(qū)別了......
這樣帶來(lái)的是嚴(yán)重的性能問(wèn)題..
現(xiàn)在重新做這些東西,我想到了2個(gè)方案,第一個(gè):
針對(duì)數(shù)據(jù)比較少的多級(jí)菜單,我們可以通過(guò)數(shù)據(jù)庫(kù)一次查詢出來(lái)所有記錄,然后通過(guò)程序進(jìn)行遞歸算法,進(jìn)行數(shù)據(jù)的轉(zhuǎn)化.
第二種:
就是數(shù)據(jù)庫(kù)設(shè)計(jì)的時(shí)候,設(shè)計(jì)成多級(jí)別的菜單,每次加載通過(guò)ajax,一點(diǎn)一點(diǎn)展開(kāi)(每一次展開(kāi)都ajax請(qǐng)求下一級(jí)的數(shù)據(jù)),這樣避免的遞歸帶來(lái)的性能損失,而且實(shí)現(xiàn)簡(jiǎn)單方便,非常適合大數(shù)據(jù)量的時(shí)候,但是,一次只能顯示一級(jí),每次都要ajax請(qǐng)求下一級(jí).
由于后臺(tái)管理,第一次就按照第一種方案來(lái)設(shè)計(jì):
首先,要設(shè)計(jì)好數(shù)據(jù)庫(kù),方便以后兩種方式擴(kuò)展,

這樣設(shè)計(jì),主要是考慮方便前臺(tái)后臺(tái)的擴(kuò)展,FId字段是一個(gè)為了方便前臺(tái)查詢而設(shè)計(jì)的,這樣設(shè)計(jì)的好處就是如果查詢比如頂級(jí)菜單下的所有產(chǎn)品,只需要根據(jù)模糊查詢前綴匹配,就能把所有的產(chǎn)品都查詢出來(lái),設(shè)計(jì)的字段還是有點(diǎn)小,IsLeaf是為了判斷是否是葉子節(jié)點(diǎn),BelongSid父級(jí)id,

前臺(tái)代碼:
復(fù)制代碼 代碼如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>產(chǎn)品類別管理</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<link href="../css/demo.css" rel="stylesheet" type="text/css" />
<script src="../scripts/jquery-1.6.2.min.js" type="text/javascript"></script>
<script src="../scripts/miniui/miniui.js" type="text/javascript"></script><link href="../scripts/miniui/themes/default/miniui.css" rel="stylesheet" type="text/css" />
<link href="../scripts/miniui/themes/icons.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="mini-toolbar">
<h1>產(chǎn)品類別管理</h1>
<div class="mini-panel" title="產(chǎn)品類別管理" iconCls="icon-add" style="width:100%;height:500px;"
showToolbar="true" showCollapseButton="true" showFooter="true"
>
<!--toolbar-->
<div property="toolbar">
</div>
<!--footer-->
<div property="footer">
</div>
<!--body-->
<ul id="tree1" class="mini-tree" url="Data/GetProductInfo.ashx?method=GetProductType" style="width:100%;height:100%;padding:5px;"
showTreeIcon="true" textField="text" idField="id" contextMenu="#treeMenu"
>
</ul>
<ul id="treeMenu" class="mini-menu" style="display:none;" onbeforeopen="onBeforeOpen">
<!-- <li name="move" iconCls="icon-move" onclick="onMoveNode">移動(dòng)節(jié)點(diǎn)</li>-->
<li class="separator"></li>
<li name="addNode" onclick="onAddNode" iconCls="icon-add">插入節(jié)點(diǎn)</li>
<li name="edit" iconCls="icon-edit" onclick="onEditNode">編輯節(jié)點(diǎn)</li>
<li name="remove" iconCls="icon-remove" onclick="onRemoveNode">刪除節(jié)點(diǎn)</li>
<li name="cancel" iconCls="icon-cancel" onclick="onCancel">取消</li>
<li class="separator"></li>
</ul>
</div>
<br /><br />
</div>
<script type="text/javascript">
mini.parse();
var AddTpye="add";
function onCancel(e){
var tree=mini.get("tree1");
var node=tree.getSelectedNode();
tree.isExpandedNode (node);
}
function onAddBefore(e) {
AddType="before";
AddItem(e);
}
function onAddAfter(e)
{
AddType="after";
AddItem(e);
}
function AddItem(e) {
var tree = mini.get("tree1");
var node = tree.getSelectedNode();
var newNode = {id:0,text:"空",pid:node.id};
mini.prompt("請(qǐng)輸入類別內(nèi)容:", "請(qǐng)輸入",
function (action, value) {
if (action == "ok"){
$.ajax({
url:"Data/GetProductInfo.ashx",
type:"post",
data:"method=AddProductType&text="+value+"&pid="+node.id+"&IsLeaf="+tree.isLeaf(node),
success:function(msg){
if(msg){
alert("添加成功!");
TreeLoad();
// newNode.text=value;
// if(node!=null){
//
// tree.addNode(newNode, AddType, node);
// }
}
else
alert("添加失敗!");
}
});
}
else {
newNode.text="空";
}
});
}
//刷新樹(shù)
function TreeLoad(){
$.ajax({
url:"Data/GetProductInfo.ashx?method=GetProductType",
type:"json",
success:function(json){
var tree = mini.get("tree1");
// alert(json);
var data= eval("("+json+")");
tree.loadData(data);
}
});
}
function onAddNode(e) {
AddType="add";
AddItem(e);
}
function onEditNode(e) {
var tree = mini.get("tree1");
var node = tree.getSelectedNode();
mini.prompt("請(qǐng)輸入類別內(nèi)容:", "請(qǐng)輸入",
function (action, value) {
if (action == "ok") {
$.ajax({
url:"Data/GetProductInfo.ashx",
type:"post",
data:"method=SaveProductType&id="+node.id+"&text="+value+"&pid="+node.pid+"&IsLeaf="+tree.isLeaf(node),
success:function(msg){
if(msg){
alert("保存成功!");
tree.setNodeText(node,value);
//TreeLoad();
}
else
alert("保存失敗!");
}
});
}
});
}
function onRemoveNode(e) {
var tree = mini.get("tree1");
var node = tree.getSelectedNode();
if (node) {
if (confirm("確定刪除選中節(jié)點(diǎn)?")) {
//這里提交到服務(wù)器
$.ajax({
url:"Data/GetProductInfo.ashx",
type:"post",
data:"method=RemoveProductType&id="+node.id,
success:function(msg){
if(msg){
tree.removeNode(node);
alert("刪除成功!");
}
else{
alert("刪除失敗!");
}
}
});
}
}
}
function onBeforeOpen(e) {
var menu = e.sender;
var tree = mini.get("tree1");
var node = tree.getSelectedNode();
// if (node && node.id == "-1") { //如果根節(jié)點(diǎn)(總根目錄,那么阻止菜單顯示)
// e.cancel = true;
// //阻止瀏覽器默認(rèn)右鍵菜單
// e.htmlEvent.preventDefault();
// return;
// }
////////////////////////////////
var editItem = mini.getbyName("edit", menu);
var removeItem = mini.getbyName("remove", menu);
var addNodeItem=mini.getbyName("addNode",menu);
//var moveItem=mini.getbyName("move",menu);
editItem.show();
removeItem.show();
addNodeItem.show();
if (node.id == "-1") {//總根目錄
removeItem.hide();
// moveItem.hide();
}
}
</script>
</body>
</html>
這一個(gè)難點(diǎn)在于json數(shù)據(jù)遞歸生成:
BLL中獲得Tree的json數(shù)據(jù)
復(fù)制代碼 代碼如下:
/// <summary>
/// 工藝品類別樹(shù)轉(zhuǎn)化為json格式
/// </summary>
/// <returns></returns>
public string craftTypeTreeToJson()
{
//傳遞的json格式
IEnumerable<crafttype> craftTypeList = new crafttypeDAL().ListAll();
StringBuilder sb = new StringBuilder("[");
foreach (crafttype root in craftTypeList)
{
if (root.Belongsid == -1)
{
sb.Append("{id:\"" + root.ID + "\",text:\"" + root.Name + "\"");
sb.Append(",pid:\"-1\"");//添加父節(jié)點(diǎn)
sb.Append(",expanded:\"false\"");
if (root.IsLeaf == "0")//如果是不是葉子節(jié)點(diǎn),那么,就要遞歸添加children:[{xxx},內(nèi)容
{
sb.Append(",children:");
GetLeafTree(ref sb, (int)root.ID, craftTypeList);//遞歸追加葉子
}
sb.Append("},");
}
}
sb.Remove(sb.Length - 1, 1); //去除掉最后一個(gè)多余的,
sb.Append("]");
return Common.FormatToJson.MiniUiToJsonForTree(sb.ToString(), "工藝品類別");
}
/// <summary>
/// 遞歸獲得父級(jí)ID下的所有類別json數(shù)據(jù)
/// </summary>
/// <param name="sb">json字符串</param>
/// <param name="parentID">父級(jí)id</param>
/// <param name="craftTypeList">類別信息集合</param>
public void GetLeafTree(ref StringBuilder sb,int parentID,IEnumerable<crafttype> craftTypeList)
{
sb.Append("[");
foreach (crafttype leaf in craftTypeList)
{
if (leaf.Belongsid == parentID) //根據(jù)雙親節(jié)點(diǎn)查找葉子
{
sb.Append("{id:\"" + leaf.ID + "\",text:\"" + leaf.Name + "\"");
sb.Append(",pid:\"" + parentID + "\"");//添加父節(jié)點(diǎn)
sb.Append(",expanded:\"false\"");
if (leaf.IsLeaf == "0")//如果是不是葉子節(jié)點(diǎn),那么,就要遞歸添加children:[{xxx},內(nèi)容
{
sb.Append(",children:");
GetLeafTree(ref sb,(int)leaf.ID, craftTypeList);//遞歸追加葉子
}
sb.Append("},");
}
}
sb.Remove(sb.Length - 1, 1); //去除掉最后一個(gè)多余的,
sb.Append("]");
}
效果圖如下:

雖然是ajax實(shí)現(xiàn),不過(guò)這個(gè)確實(shí)ajax一次性把數(shù)據(jù)全部加載進(jìn)去,這樣對(duì)性能有嚴(yán)重的損失,不過(guò)考慮是后臺(tái),所以,沒(méi)做處理,不過(guò)最好還是用第二種方法設(shè)計(jì),那種方法是最好的解決方法,也適合前臺(tái)的數(shù)據(jù)展示.
第二種方法正在實(shí)踐中………
相關(guān)文章
asp.net 學(xué)習(xí)之路 項(xiàng)目整體框架簡(jiǎn)單的搭建
最近剛學(xué)了些關(guān)于asp.net mvc方面的知識(shí),于是了要拿個(gè)小項(xiàng)目來(lái)練練手,提高下自己的code能力跟思維能力2012-12-12
vs2017軟鏈接失效而導(dǎo)致無(wú)法進(jìn)入安裝界面的解決方法
這篇文章主要為大家詳細(xì)介紹了vs2017軟鏈接失效而導(dǎo)致無(wú)法進(jìn)入安裝界面的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09
ASP.NET(C#) Web Api通過(guò)文件流下載文件的實(shí)例
這篇文章主要介紹了ASP.NET(C#) Web Api通過(guò)文件流下載文件的方法,提供源碼下載,需要的朋友可以參考下。2016-06-06
Repeater綁定dictionary數(shù)據(jù)源代碼及報(bào)錯(cuò)解決
為大家講解下Repeater綁定dictionary數(shù)據(jù)源以及報(bào)錯(cuò)處理的方法,感興趣的朋友可以參考下哈,希望對(duì)你有所幫助2013-04-04
使用.NET?6開(kāi)發(fā)TodoList應(yīng)用之領(lǐng)域?qū)嶓w創(chuàng)建原理和思路
雖然TodoList是一個(gè)很簡(jiǎn)單的應(yīng)用,業(yè)務(wù)邏輯并不復(fù)雜,至少在這個(gè)系列文章中我并不想使其過(guò)度復(fù)雜,接下來(lái)通過(guò)本文給大家介紹使用.NET?6開(kāi)發(fā)TodoList應(yīng)用之領(lǐng)域?qū)嶓w創(chuàng)建思路及原理,需要的朋友可以參考下2021-12-12
ASP.NET全棧開(kāi)發(fā)教程之前后臺(tái)校驗(yàn)結(jié)合詳解
這篇文章主要給大家介紹了關(guān)于ASP.NET全棧開(kāi)發(fā)教程之前后臺(tái)校驗(yàn)結(jié)合的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07
win7系統(tǒng)下 vs2010 調(diào)式就關(guān)閉要重啟處理方法
最近經(jīng)常出現(xiàn)只要一使用vs2010進(jìn)行調(diào)試,就提示關(guān)閉并要重啟,好煩,度娘了半天,總結(jié)下來(lái)解決方法,親測(cè)可用哦。2014-08-08

