2012年4月28日星期六

一步一步asp.net_ajax类别Tree生成

一步一步asp.net_ajax类别Tree生成

关于类别树的多级是一个刚接触ajax和多级类别很头痛的问题,针对那种商品种类繁多,级别层次多更是麻烦的问题,去年刚学asp.net,实验室的同学曾经这样做过,递归sql,现在看了惊心动魄.........呃...........

image

虽然实现了类别多级的问题这样带来的后果确实无穷无尽的.............

递归查询,和双循环嵌套的执行sql语句没什么区别了......

这样带来的是严重的性能问题..

现在重新做这些东西,我想到了2个方案,第一个:

针对数据比较少的多级菜单,我们可以通过数据库一次查询出来所有记录,然后通过程序进行递归算法,进行数据的转化.

第二种:

就是数据库设计的时候,设计成多级别的菜单,每次加载通过ajax,一点一点展开(每一次展开都ajax请求下一级的数据),这样避免的递归带来的性能损失,而且实现简单方便,非常适合大数据量的时候,但是,一次只能显示一级,每次都要ajax请求下一级.

由于后台管理,第一次就按照第一种方案来设计:

首先,要设计好数据库,方便以后两种方式扩展,

image

这样设计,主要是考虑方便前台后台的扩展,FId字段是一个为了方便前台查询而设计的,这样设计的好处就是如果查询比如顶级菜单下的所有产品,只需要根据模糊查询前缀匹配,就能把所有的产品都查询出来,设计的字段还是有点小,IsLeaf是为了判断是否是叶子节点,BelongSid父级id,

image

前台代码:

   1:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   2:   
   3:  <html ="http://www.w3.org/1999/xhtml">
   4:  <head>
   5:      <title>产品类别管理</title>
   6:      <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
   7:      <link href="../css/demo.css" rel="stylesheet" type="text/css" />
   8:   
   9:      <script src="../scripts/jquery-1.6.2.min.js" type="text/javascript"></script>
  10:      <script src="../scripts/miniui/miniui.js" type="text/javascript"></script><link href="../scripts/miniui/themes/default/miniui.css" rel="stylesheet" type="text/css" />
  11:      <link href="../scripts/miniui/themes/icons.css" rel="stylesheet" type="text/css" />    
  12:   
  13:  </head>
  14:  <body>
  15:   
  16:  <div class="mini-toolbar">
  17:      <h1>产品类别管理</h1>
  18:      
  19:  <div class="mini-panel" title="产品类别管理" iconCls="icon-add" style="width:100%;height:500px;" 
  20:      showToolbar="true" showCollapseButton="true" showFooter="true" 
  21:  >
  22:      <!--toolbar-->
  23:      <div property="toolbar"> 
  24:      </div>
  25:      <!--footer-->
  26:      <div property="footer">
  27:      
  28:      </div>
  29:      <!--body-->
  30:        
  31:            <ul id="tree1" class="mini-tree" url="Data/GetProductInfo.ashx?method=GetProductType" style="width:100%;height:100%;padding:5px;" 
  32:          showTreeIcon="true" textField="text" idField="id"   contextMenu="#treeMenu"
  33:          
  34:          >        
  35:      </ul>  
  36:        <ul id="treeMenu" class="mini-menu" style="display:none;" onbeforeopen="onBeforeOpen">
  37:          
  38:        <!--  <li name="move" iconCls="icon-move" onclick="onMoveNode">移动节点</li>-->
  39:          <li class="separator"></li>
  40:   
  41:         
  42:                  <li name="addNode" onclick="onAddNode" iconCls="icon-add">插入节点</li>         
  43:          
  44:          <li name="edit" iconCls="icon-edit" onclick="onEditNode">编辑节点</li>
  45:          <li name="remove" iconCls="icon-remove" onclick="onRemoveNode">删除节点</li>        
  46:          <li name="cancel" iconCls="icon-cancel" onclick="onCancel">取消</li>
  47:    <li class="separator"></li>
  48:      </ul>
  49:   
  50:   
  51:  </div>
  52:   
  53:  <br /><br />
  54:      
  55:  </div>
  56:      
  57:   
  58:      <script type="text/javascript">
  59:          mini.parse();
  60:          var AddTpye="add";
  61:   
  62:          function onCancel(e){
  63:          var tree=mini.get("tree1");
  64:          var node=tree.getSelectedNode();
  65:           tree.isExpandedNode (node);
  66:         
  67:          }
  68:          function onAddBefore(e) {
  69:            AddType="before";
  70:          AddItem(e);
  71:          }
  72:          function onAddAfter(e)
  73:          {
  74:          AddType="after";
  75:          AddItem(e);
  76:          }
  77:          function AddItem(e) {
  78:             
  79:              var tree = mini.get("tree1");
  80:              var node = tree.getSelectedNode();
  81:             
  82:              var newNode = {id:0,text:"空",pid:node.id};
  83:              mini.prompt("请输入类别内容:", "请输入",
  84:              function (action, value) {
  85:                  if (action == "ok"){
  86:                       $.ajax({
  87:                          url:"Data/GetProductInfo.ashx",
  88:                          type:"post",
  89:                          data:"method=AddProductType&text="+value+"&pid="+node.id+"&IsLeaf="+tree.isLeaf(node),
  90:                          success:function(msg){
  91:                              if(msg){
  92:                              alert("添加成功!");
  93:                              TreeLoad();
  94:  //                            newNode.text=value;
  95:  //                                     if(node!=null){
  96:  //                                       
  97:  //                                          tree.addNode(newNode, AddType, node);
  98:  //                                          }    
  99:                                             
 100:                              }
 101:                              else
 102:                              alert("添加失败!");
 103:                
 104:                           }
 105:                        });
 106:                 
 107:                  }
 108:                 else {
 109:                  newNode.text="空";
 110:                 }
 111:             });
 112:           }
 113:   
 114:            
 115:        
 116:          //刷新树
 117:          function TreeLoad(){
 118:          $.ajax({
 119:          url:"Data/GetProductInfo.ashx?method=GetProductType",
 120:          type:"json",
 121:          success:function(json){
 122:            var tree = mini.get("tree1");  
 123:              //  alert(json);
 124:              var data=  eval("("+json+")");
 125:                 tree.loadData(data);
 126:                 }
 127:          });
 128:          
 129:          }
 130:          function onAddNode(e) {
 131:          AddType="add";
 132:          AddItem(e);
 133:              
 134:          }
 135:          function onEditNode(e) {
 136:              var tree = mini.get("tree1");
 137:              var node = tree.getSelectedNode();
 138:         mini.prompt("请输入类别内容:", "请输入",
 139:              function (action, value) {
 140:                  if (action == "ok") {
 141:                   $.ajax({
 142:                      url:"Data/GetProductInfo.ashx",
 143:                      type:"post",
 144:                      data:"method=SaveProductType&id="+node.id+"&text="+value+"&pid="+node.pid+"&IsLeaf="+tree.isLeaf(node),
 145:                      success:function(msg){
 146:                     if(msg){
 147:                      alert("保存成功!");
 148:                        tree.setNodeText(node,value);
 149:               
 150:                        //TreeLoad();
 151:                      }
 152:                      else
 153:                      alert("保存失败!");
 154:                      }
 155:                      }); 
 156:                    
 157:                  }
 158:                  
 159:              });              
 160:          }
 161:   
 162:          function onRemoveNode(e) {
 163:              var tree = mini.get("tree1");
 164:              var node = tree.getSelectedNode();
 165:            
 166:               if (node) {
 167:                  if (confirm("确定删除选中节点?")) {
 168:                     
 169:                      //这里提交到服务器
 170:                      $.ajax({
 171:                      url:"Data/GetProductInfo.ashx",
 172:                      type:"post",
 173:                      data:"method=RemoveProductType&id="+node.id,
 174:                      success:function(msg){
 175:                       if(msg){
 176:                       tree.removeNode(node);
 177:                       
 178:                       alert("删除成功!");
 179:                       }
 180:                       else{
 181:                       alert("删除失败!");
 182:                       }
 183:                     
 184:                     
 185:                   
 186:                      }
 187:                      });
 188:                      
 189:                  }
 190:              }
 191:          }
 192:   
 193:           function onBeforeOpen(e) {
 194:           
 195:              var menu = e.sender;
 196:              var tree = mini.get("tree1");
 197:   
 198:              var node = tree.getSelectedNode();
 199:  //            if (node && node.id == "-1") { //如果根节点(总根目录,那么阻止菜单显示)
 200:  //                e.cancel = true;
 201:  //                //阻止浏览器默认右键菜单
 202:  //                e.htmlEvent.preventDefault();
 203:  //                return;
 204:  //            }
 205:   
 206:              ////////////////////////////////
 207:              var editItem = mini.getbyName("edit", menu);
 208:              var removeItem = mini.getbyName("remove", menu);
 209:              var addNodeItem=mini.getbyName("addNode",menu);
 210:              //var moveItem=mini.getbyName("move",menu);
 211:               editItem.show();
 212:              removeItem.show();
 213:              addNodeItem.show();
 214:              if (node.id == "-1") {//总根目录
 215:                  removeItem.hide();
 216:                // moveItem.hide();
 217:                 
 218:              }
 219:           
 220:              }
 221:   
 222:      </script>
 223:   
 224:  </body>
 225:  </html>
这一个难点在于json数据递归生成:BLL中获得Tree的json数据
   1:      /// <summary>
   2:         /// 工艺品类别树转化为json格式
   3:         /// </summary>
   4:         /// <returns></returns>
   5:         public string craftTypeTreeToJson()
   6:         {
   7:             //传递的json格式
   8:                  
   9:             IEnumerable<crafttype> craftTypeList = new crafttypeDAL().ListAll();
  10:             StringBuilder sb = new StringBuilder("[");
  11:             
  12:             foreach (crafttype root in craftTypeList)
  13:             {
  14:                 if (root.Belongsid == -1)
  15:                 {
  16:                     sb.Append("{id:\"" + root.ID + "\",text:\"" + root.Name + "\"");
  17:                     sb.Append(",pid:\"-1\"");//添加父节点
  18:                     sb.Append(",expanded:\"false\"");
  19:                     if (root.IsLeaf == "0")//如果是不是叶子节点,那么,就要递归添加children:[{xxx},内容
  20:                     {
  21:                         sb.Append(",children:");
  22:                         GetLeafTree(ref sb, (int)root.ID, craftTypeList);//递归追加叶子
  23:                     }
  24:                     sb.Append("},");
  25:                 }
  26:               
  27:             }
  28:             sb.Remove(sb.Length - 1, 1);   //去除掉最后一个多余的,
  29:             sb.Append("]");
  30:             return Common.FormatToJson.MiniUiToJsonForTree(sb.ToString(), "工艺品类别");
  31:        
  32:         }
  33:         /// <summary>
  34:         /// 递归获得父级ID下的所有类别json数据
  35:         /// </summary>
  36:         /// <param name="sb">json字符串</param>
  37:         /// <param name="parentID">父级id</param>
  38:         /// <param name="craftTypeList">类别信息集合</param>
  39:         public void GetLeafTree(ref StringBuilder sb,int parentID,IEnumerable<crafttype> craftTypeList)
  40:         {
  41:             sb.Append("[");
  42:             foreach (crafttype leaf in craftTypeList)
  43:             {
  44:                 if (leaf.Belongsid == parentID) //根据双亲节点查找叶子
  45:                 {
  46:                     sb.Append("{id:\"" + leaf.ID + "\",text:\"" + leaf.Name + "\"");
  47:                     sb.Append(",pid:\"" + parentID + "\"");//添加父节点
  48:                     sb.Append(",expanded:\"false\"");
  49:                     if (leaf.IsLeaf == "0")//如果是不是叶子节点,那么,就要递归添加children:[{xxx},内容
  50:                     {
  51:                         sb.Append(",children:");
  52:                         GetLeafTree(ref sb,(int)leaf.ID, craftTypeList);//递归追加叶子
  53:   
  54:                     }
  55:                     sb.Append("},");
  56:                 }
  57:             }
  58:             sb.Remove(sb.Length - 1, 1);   //去除掉最后一个多余的,
  59:             sb.Append("]");
  60:   
  61:           
  62:          
  63:         
  64:         }
效果图如下:
image
虽然是ajax实现,不过这个确实ajax一次性把数据全部加载进去,这样对性能有严重的损失,不过考虑是后台,所以,没做处理,不过最好还是用第二种方法设计,那种方法是最好的解决方法,也适合前台的数据展示.
第二种方法正在实践中………
一直在努力,从未曾放弃,努力学习中.....欢迎一起学习.net!
TAG: