关于类别树的多级是一个刚接触ajax和多级类别很头痛的问题,针对那种商品种类繁多,级别层次多更是麻烦的问题,去年刚学asp.net,实验室的同学曾经这样做过,递归sql,现在看了惊心动魄.........呃...........
虽然实现了类别多级的问题这样带来的后果确实无穷无尽的.............
递归查询,和双循环嵌套的执行sql语句没什么区别了......
这样带来的是严重的性能问题..
现在重新做这些东西,我想到了2个方案,第一个:
针对数据比较少的多级菜单,我们可以通过数据库一次查询出来所有记录,然后通过程序进行递归算法,进行数据的转化.
第二种:
就是数据库设计的时候,设计成多级别的菜单,每次加载通过ajax,一点一点展开(每一次展开都ajax请求下一级的数据),这样避免的递归带来的性能损失,而且实现简单方便,非常适合大数据量的时候,但是,一次只能显示一级,每次都要ajax请求下一级.
由于后台管理,第一次就按照第一种方案来设计:
首先,要设计好数据库,方便以后两种方式扩展,
这样设计,主要是考虑方便前台后台的扩展,FId字段是一个为了方便前台查询而设计的,这样设计的好处就是如果查询比如顶级菜单下的所有产品,只需要根据模糊查询前缀匹配,就能把所有的产品都查询出来,设计的字段还是有点小,IsLeaf是为了判断是否是叶子节点,BelongSid父级id,
前台代码:
1: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2:
3: <html xmlns="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数据递归生成:
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: }
效果图如下:
虽然是ajax实现,不过这个确实ajax一次性把数据全部加载进去,这样对性能有严重的损失,不过考虑是后台,所以,没做处理,不过最好还是用第二种方法设计,那种方法是最好的解决方法,也适合前台的数据展示.
第二种方法正在实践中………