在Yii框架下实现无限层级管理,首先要找到合适的前端实现方法,把前端所需数据听过后端传入。为此,我在前端实现上找到了zTree这款无限层级jQuery的插件。
首先要在controller,manager写好相关方法。由于zTree要的数据格式是JSON,所以需要对从数据库里提取的值作编码后再传入到前端,这里用到了json_encode,之后还需要JSON.parse将编码后的json字符串传化成json对象。用法可见:http://blog.csdn.net/lowkeysk/article/details/8175195 Yii框架下的后台代码如下:
Controller:
<?php class QueryTagController extends Controller { public function actionLevel() { //$this->tpl->assign("main_step", "main"); $catinfos = $this->QueryTag->getcatarray(); $catinfo = json_encode($catinfos); $this->tpl->assign('catinfo', $catinfo); $this->tpl->display('category/querytags.html'); } //添加节点 public function actionAddNode() { try { $transaction = Yii::app()->db->beginTransaction(); $result = $this->QueryTag->AddNode($_POST); $transaction->commit(); } catch(Exception $ex){ if(isset($transaction)) { $transaction->rollback(); } $this->tool->goback($ex->getMessage() ); } $catinfos = $this->QueryTag->getcatarray(); $catinfo = json_encode($catinfos); echo $catinfo; } //修改节点名称 public function actionEditNode() { try { $transaction = Yii::app()->db->beginTransaction(); $result = $this->QueryTag->EditNode($_POST); $transaction->commit(); } catch(Exception $ex){ if(isset($transaction)) { $transaction->rollback(); } $this->tool->goback($ex->getMessage() ); } } //删除节点 public function actionDeleteNode() { try { $transaction = Yii::app()->db->beginTransaction(); $result = $this->QueryTag->DeleteNode($_POST); $transaction->commit(); } catch(Exception $ex){ if(isset($transaction)) { $transaction->rollback(); } $this->tool->goback($ex->getMessage() ); } } } ?>
Manager:
<?php class QueryTagManager extends Manager{ /** * 获取全部分类信息 */ public function getcatarray() { $sql=" SELECT id, name, parent, level FROM query_tags ORDER BY id asc "; $category = Yii::app()->db->createCommand($sql)->queryAll(); $arr = array(); foreach($category as $categoryinfo){ //对每个分类进行循环。 $item = array(); $item['id'] = $categoryinfo['id']; $item['pId'] = $categoryinfo['parent']; $item['name'] = $categoryinfo['name']; $arr[] = $item; } return $arr; } //添加节点 public function AddNode($data){ $querytag = new QueryTag(); //$querytag->id = $data['id']; $querytag->name = $data['name']; $querytag->parent = $data['pId']; $querytag->level = $data['level']; $querytag->save(); } //修改节点名称 public function EditNode($data){ $querytag = QueryTag::model()->findByPk($data['id']); $querytag->name = $data['name']; $querytag->save(); } //删除节点 public function DeleteNode($data){ QueryTag::model()->deleteByPK($data['id']); } } ?>
对于前端zTree的调用,一定要仔细阅读demo,和API的用法。由于项目里的数据表的id是自增的,所以要注意添加节点的返回值得问题,可参考:http://www.oschina.net/question/2249788_181333 同时一定要理解JSON对象的含义。我这里就犯了一些错误,导致treeNode.children的值一直没取出来。
对于将数据压入后台,可采取异步加载的方式,但一定要注意异步方法的使用事项,记得将post里的数据通过success:callback function去添加到zNodes里去。尽量不要重新初始化树结构。
基本代码如下:
<!DOCTYPE html> <HTML> <HEAD> <TITLE> 查询词标签管理</TITLE> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" href="{$BASE_DIR_MODULE}/css/ztree/demo.css" type="text/css"> <link rel="stylesheet" href="{$BASE_DIR_MODULE}/css/ztree/zTreeStyle/zTreeStyle.css" type="text/css"> <script type="text/javascript" src="{$BASE_DIR_MODULE}/js/ztree/jquery-1.4.4.min.js"></script> <script type="text/javascript" src="{$BASE_DIR_MODULE}/js/ztree/jquery.ztree.core-3.5.js"></script> <script type="text/javascript" src="{$BASE_DIR_MODULE}/js/ztree/jquery.ztree.excheck-3.5.js"></script> <script type="text/javascript" src="{$BASE_DIR_MODULE}/js/ztree/jquery.ztree.exedit-3.5.js"></script> <script > var catinfo = '{$catinfo}'; </script> {literal} <SCRIPT type="text/javascript"> <!-- var setting = { ........//这里就不写了,参考zTree的DEMO }; var zNodes = JSON.parse(catinfo); var log, className = "dark"; function beforeDrag(treeId, treeNodes) { return false; } function beforeEditName(treeId, treeNode) { className = (className === "dark" ? "":"dark"); showLog("[ "+getTime()+" beforeEditName ] " + treeNode.name); var zTree = $.fn.zTree.getZTreeObj("treeDemo"); zTree.selectNode(treeNode); //return confirm("进入节点 -- " + treeNode.name + " 的编辑状态吗?"); } function beforeRemove(treeId, treeNode) { className = (className === "dark" ? "":"dark"); showLog("[ "+getTime()+" beforeRemove ] " + treeNode.name); var zTree = $.fn.zTree.getZTreeObj("treeDemo"); zTree.selectNode(treeNode); return confirm("确认删除 节点 -- " + treeNode.name + " 吗?"); zTree.selectNode(treeNode); return confirm("确认删除 节点 -- " + treeNode.name + " 吗?"); } function onRemove(e, treeId, treeNode) { showLog("[ "+getTime()+" onRemove ] " + treeNode.name); var id = treeNode.id; var name = treeNode.name; var pId = treeNode.pId; var url = "DeleteNode"; var data = {}; data['id'] = id; data['name'] = name; data['pId'] = pId; $.ajax({ type:"POST", url:url, data:data, success: function(data){ } }); } function beforeRename(treeId, treeNode, newName, isCancel) { className = (className === "dark" ? "":"dark"); showLog((isCancel ? "<span style='color:red'>":"") + "[ "+getTime()+" beforeRename ] " + treeNode.name + (isCancel ? "</span>":"")); if (newName.length == 0) { alert("节点名称不能为空."); var zTree = $.fn.zTree.getZTreeObj("treeDemo"); setTimeout(function(){zTree.editName(treeNode)}, 10); return false; } return true; } function onRename(e, treeId, treeNode, isCancel) { showLog((isCancel ? "<span style='color:red'>":"") + "[ "+getTime()+" onRename ] " + treeNode.name + (isCancel ? "</span>":"")); var id = treeNode.id; var name = treeNode.name; var pId = treeNode.pId; var url = "EditNode"; var data = {}; data['id'] = id; data['name'] = name; data['pId'] = pId; $.ajax({ type:"POST", url:url, data:data, success: function(data){ alert("节点名修改成功!") } }); } function showRemoveBtn(treeId, treeNode) { return !treeNode.isFirstNode; } function showRenameBtn(treeId, treeNode) { return !treeNode.isLastNode; } function showLog(str) { } function showLog(str) { if (!log) log = $("#log"); log.append("<li class='"+className+"'>"+str+"</li>"); if(log.children("li").length > 8) { log.get(0).removeChild(log.children("li")[0]); } } function addHoverDom(treeId, treeNode) { var sObj = $("#" + treeNode.tId + "_span"); if (treeNode.editNameFlag || $("#addBtn_"+treeNode.tId).length>0) return; var addStr = "<span class='button add' id='addBtn_" + treeNode.tId + "' title='add node' onfocus='this.blur();'></span>"; sObj.after(addStr); var btn = $("#addBtn_"+treeNode.tId); if (btn) btn.bind("click", function(){ var pId = treeNode.id; //console.log("pid = " + pId); var name = "new node"; var level = treeNode.level + 2 ; var url = "AddNode"; var data = {}; data['name'] = name; data['pId'] = pId; data['level'] = level; $.ajax({ type:"POST", url:url, data:data, success: function(data){ //zNodes=JSON.parse(data); //$.fn.zTree.init($("#treeDemo"), setting, zNodes); data=JSON.parse(data); var index = data.length - 1; if(data != ""){ var zTree = $.fn.zTree.getZTreeObj("treeDemo"); zTree.addNodes(treeNode, {id:data[index].id, pId : data[index].pId, name : name, level: level}); var nindex = treeNode.children.length -1; zTree.editName(treeNode.children[nindex]); alert("节点添加成功!"); }else { alert("节点添加失败!"); } } }); return false; }); }; function removeHoverDom(treeId, treeNode) { $("#addBtn_"+treeNode.tId).unbind().remove(); function removeHoverDom(treeId, treeNode) { $("#addBtn_"+treeNode.tId).unbind().remove(); }; function selectAll() { var zTree = $.fn.zTree.getZTreeObj("treeDemo"); zTree.setting.edit.editNameSelectAll = $("#selectAll").attr("checked"); } $(document).ready(function(){ $.fn.zTree.init($("#treeDemo"), setting, zNodes); $("#selectAll").bind("click", selectAll); }); //--> </SCRIPT> <style type="text/css"> .ztree li span.button.add {margin-left:2px; margin-right: -1px; background-position:-144px 0; vertical-align:top; *vertical-align:middle} </style> {/literal} </HEAD> <BODY> <div class="content_wrap"> <div class="zTreeDemoBackground left"> <ul id="treeDemo" class="ztree"></ul> </div> </div> </BODY> </HTML>
要学会在jQuery模式下,通过使用console.log()去查看调试信息。以及浏览器的控制台console,帮助定位和查找找问题。