zTree 是一个依靠 jQuery 实现的多功能 “树插件”。优异的性能、灵活的配置、多种功能的组合是 zTree 最大优点。大家可以从zTree 的官网下载和学习。
我这里通过自己的实践,简单介绍一下在.net MVC 环境下,如何实现 ztree 展示和管理树型结构的。
首先我们先假设一下任务,管理新闻的分类,先介绍一下数据结构。
我们还是先建立一个表结构对象和访问控制类
//新闻分类(VON_Catalog) #region"新闻分类信息类声明" namespaceVonPortal.Web.Models { ///<summary>新闻分类信息类</summary> publicclassCatalogInfo { #region"Constructors" ///<summary> ///构造函数 ///</summary> publicCatalogInfo() { } ///<summary> ///含初始化构造函数 ///</summary> ///<paramname="ID">序号</param> ///<paramname="CatalogName">分类名称</param> ///<paramname="PID">父类序号</param> ///<paramname="DisplayOrder">显示序号</param> ///<paramname="Note">分类说明</param> publicCatalogInfo(intID,stringCatalogName,intPID,intDisplayOrder,stringNote) { this.ID=ID; this.CatalogName=CatalogName; this.PID=PID; this.DisplayOrder=DisplayOrder; this.Note=Note; } #endregion #region"PublicProperties" ///<summary>序号</summary> [required] [Display(Name="序号")] publicintID{get;set;} ///<summary>分类名称</summary> [Display(Name="分类名称")] publicstringCatalogName{get;set;} ///<summary>父类序号</summary> [required] [Display(Name="父类序号")] publicintPID{get;set;} ///<summary>显示序号</summary> [Display(Name="显示序号")] publicintDisplayOrder{get;set;} ///<summary>分类说明</summary> [Display(Name="分类说明")] publicstringNote{get;set;} #endregion } } #endregion #region"新闻分类信息基础控制类声明" namespaceVonPortal.Web.Operators { ///<summary>新闻分类控制类</summary> publicclassCatalogCtrl { privateCatalogDataProviderdataProvider=null; ///<summary>启动数据库事务</summary> publicIDbTransactionBeginTrans() { dataProvider=CatalogDataProvider.CreateProvider(); returndataProvider.DBBeginTrans(); } ///<summary>含数据库事务的构造函数</summary> publicCatalogCtrl(IDbTransactionDBTrans) { if(DBTrans==null) dataProvider=CatalogDataProvider.Instance(); else { dataProvider=CatalogDataProvider.CreateProvider(); dataProvider.DBTrans=DBTrans; } } //ReaddataandwritetoCatalogInfoclass privatevoidsetInfoValue(IDataReaderreader,CatalogInfoinfo) { info.ID=reader.GetInt32(0);//序号 info.CatalogName=reader.GetString(1);//分类名称 info.PID=reader.GetInt32(2);//父类序号 info.DisplayOrder=reader.GetInt32(3);//显示序号 info.Note=reader.GetString(4);//分类说明 } ///<summary>检验Catalog信息</summary> publicstringCheck(CatalogInfoinfo) { stringerrInfo=""; returnerrInfo; } ///<summary>得到本节点的下属节点新的序号</summary> publicintNewIdx(intPID) { returndataProvider.GetLasterOrder(PID)+1; } ///<summary> ///根据主键PK_Catalog提取信息 ///</summary> ///<paramname="ID">序号</param> publicCatalogInfoGetByCatalog(intID) { IDataReaderreader=dataProvider.GetByCatalog(ID); if(!reader.Read()) { reader.Close(); returnnull; } CatalogInfoinfo=newCatalogInfo(); setInfoValue(reader,info); reader.Close(); returninfo; } ///<summary>得到所有信息</summary> publicList<CatalogInfo>List() { List<CatalogInfo>list=newList<CatalogInfo>(); IDataReaderreader=dataProvider.List(); while(reader.Read()) { CatalogInfoinfo=newCatalogInfo(); setInfoValue(reader,info); list.Add(info); } reader.Close(); returnlist; } ///<summary>根据主键IDX_Catalog提取信息</summary> ///<paramname="PID">父类序号</param> publicList<CatalogInfo>ListByCatalog(intPID) { List<CatalogInfo>list=newList<CatalogInfo>(); IDataReaderreader=dataProvider.ListByCatalog(PID); while(reader.Read()) { CatalogInfoinfo=newCatalogInfo(); setInfoValue(reader,info); list.Add(info); } reader.Close(); returnlist; } ///<summary>保存Catalog信息</summary> ///<paramname="info">信息类</param> publicboolSave(CatalogInfoinfo) { info.ID=dataProvider.Save(info.ID,info.CatalogName,info.PID,info.DisplayOrder,info.Note); returninfo.ID>0; } ///<summary>添加Catalog信息</summary> ///<paramname="info">信息类</param> publicintAdd(CatalogInfoinfo) { info.ID=dataProvider.Add(info.CatalogName,info.Note); returninfo.ID; } ///<summary>修改Catalog信息</summary> ///<paramname="info">信息类</param> publicboolEdit(CatalogInfoinfo) { returndataProvider.Edit(info.ID,info.Note)>0; } ///<summary>根据PK_Catalog删除Catalog信息</summary> ///<paramname="ID">序号</param> publicintDel(intID) { returndataProvider.Del(ID); } } } #endregion #region"新闻分类信息操作控制类声明" namespaceVonPortal.Web.Tasks { ///<summary>新闻分类控制类</summary> publicclassCatalogTask:CatalogCtrl { ///<summary>含数据库事务的构造函数</summary> publicCatalogTask(IDbTransactionDBTrans):base(DBTrans) { } ///<summary> ///根据主键PK_Catalog提取信息 ///</summary> ///<paramname="ID">序号</param> publicnewTask<CatalogInfo>GetByCatalog(intID) { returnTask.Run(()=> { returnbase.GetByCatalog(ID); }); } ///<summary>根据主键IDX_Catalog提取信息</summary> ///<paramname="PID">父类序号</param> publicnewTask<List<CatalogInfo>>ListByCatalog(intPID) { returnTask.Run(()=> { returnbase.ListByCatalog(PID); }); } ///<summary>保存Catalog信息</summary> ///<paramname="info">信息类</param> publicnewTask<bool>Save(CatalogInfoinfo) { returnTask.Run(()=> { returnbase.Save(info); }); } ///<summary>添加Catalog信息</summary> ///<paramname="info">信息类</param> publicnewTask<int>Add(CatalogInfoinfo) { returnTask.Run(()=> { returnbase.Add(info); }); } ///<summary>修改Catalog信息</summary> ///<paramname="info">信息类</param> publicnewTask<bool>Edit(CatalogInfoinfo) { returnTask.Run(()=> { returnbase.Edit(info); }); } ///<summary>根据PK_Catalog删除Catalog信息</summary> ///<paramname="ID">序号</param> publicnewTask<int>Del(intID) { returnTask.Run(()=> { returnbase.Del(ID); }); } } } #endregion #region"新闻分类信息数据库访问基类声明" namespaceVonPortal.Web.Data { ///<summary> ///数据及操作控制层 ///<seealsocref="VonPortal.Web.Business.CatalogInfo"/> ///<seealsocref="VonPortal.Web.Business.CatalogCtrl"/> ///</summary> publicabstractclassCatalogDataProvider:DataProvider { #regionShared/StaticMethods //singletonreferencetotheinstantiatedobject privatestaticCatalogDataProviderobjProvider=null; ///<summary> ///constructor ///</summary> staticCatalogDataProvider() { objProvider=CreateProvider(); } ///<summary> ///dynamicallycreateprovider ///</summary> ///<returns>returntheprovider</returns> publicstaticCatalogDataProviderCreateProvider() { return(CatalogDataProvider)VonPortal.Web.Reflection.CreateDataProvider("von","NewsModule","VonPortal.Web.Data.CatalogDataProvider"); } ///<summary> ///TheinstanceofCatalogDataProvider. ///</summary> ///<returns>returntheprovider</returns> publicstaticCatalogDataProviderInstance() { if(objProvider==null)objProvider=CreateProvider(); returnobjProvider; } #endregion #region"CatalogAbstractMethods" ///<summary>根据主键PK_Catalog提取信息</summary> publicabstractIDataReaderGetByCatalog(intID); ///<summary>得到本节点的最后节点序号</summary> publicabstractintGetLasterOrder(intPID); ///<summary>根据主键IDX_Catalog提取信息</summary> publicabstractIDataReaderListByCatalog(intPID); ///<summary>提取全部信息</summary> publicabstractIDataReaderList(); ///<summary>保存Catalog信息</summary> publicabstractintSave(intID,stringNote); ///<summary>添加Catalog信息</summary> publicabstractintAdd(stringCatalogName,stringNote); ///<summary>修改Catalog信息</summary> publicabstractintEdit(intID,stringNote); ///<summary>根据PK_Catalog删除Catalog信息</summary> publicabstractintDel(intID); #endregion } } #endregion
最后的VonPortal.Web.Data.CatalogDataProvider是数据库访问接口类,您可以根据自己的实际需求建立真实的数据库访问类,完成真正的数据库访问,我这里就不在详述了,下面将介绍今天的主角 zTree。大家可以通过 zTree 网上 API 来深入了解其代码编写规则,也可以下载Demo来进行研究。
首先按照常规我们先建立后台处理的Model和Controller。
usingSystem.ComponentModel.DataAnnotations; //新闻分类(VON_Catalog) namespaceVonPortal.Web.Modules { publicclassCatalogModel { ///<summary>序号</summary> [required] [Display(Name="序号")] publicintID{get;set;} ///<summary>分类名称</summary> [Display(Name="分类名称")] publicstringCatalogName{get;set;} ///<summary>父类序号</summary> [required] [Display(Name="父类序号")] publicintPID{get;set;} ///<summary>显示序号</summary> [Display(Name="显示序号")] publicintDisplayOrder{get;set;} ///<summary>分类说明</summary> [Display(Name="分类说明")] publicstringNote{get;set;} } }
usingSystem.Collections.Generic; usingSystem.Web.Mvc; usingVonPortal.Web.Models; usingVonPortal.Web.Operators; namespaceVonPortal.Web.Modules.Controllers { publicclassNewsController:Controller { publicActionResultNewsCatalogManager() { returnPartialView(); } ///<summary> ///ajax添加一个新闻分类 ///</summary> ///<paramname="PID">上级序号</param> ///<paramname="CatalogName">分类名称</param> ///<paramname="Note">分类说明</param> ///<returns></returns> [HttpPost] publicActionResultNewCatalog(intPID,stringNote) { CatalogCtrlctrl=newCatalogCtrl(null); CatalogInfoinfo=newCatalogInfo(0,CatalogName,PID,Note); info.DisplayOrder=ctrl.NewIdx(PID); ctrl.Add(info); returnJson(new{bRet=true,sMsg="添加成功",html=info.ID.ToString()},"text/html"); } ///<summary> ///ajax修改一个分类信息 ///</summary> ///<paramname="PID">上级序号</param> ///<paramname="CatalogName">分类名称</param> ///<paramname="Note">分类说明</param> ///<returns></returns> [HttpPost] publicActionResultEditCatalog(intID,stringNote) { CatalogCtrlctrl=newCatalogCtrl(null); CatalogInfoinfo=ctrl.GetByCatalog(ID); info.CatalogName=CatalogName; info.Note=Note; ctrl.Edit(info); returnJson(new{bRet=true,sMsg="修改成功"},"text/html"); } ///<summary> ///ajax删除一个新闻分类 ///</summary> ///<paramname="ID">分类序号</param> ///<returns></returns> [HttpPost] publicActionResultDeleteCatalog(intID) { CatalogCtrlctrl=newCatalogCtrl(null); ctrl.Del(ID); returnJson(new{bRet=true,sMsg="删除成功"},"text/html"); } ///<summary> ///ajax加载所有的新闻分类 ///</summary> publicvoidLoadCatalog() { List<CatalogInfo>lst=(newCatalogCtrl(null)).List(); Response.Write("{["); foreach(CatalogInfoinfoinlst) { Response.Write("{ID:'"+info.ID.ToString()+"'"); Response.Write(",CatalogName:'"+info.CatalogName+"'"); Response.Write(",PID:'"+info.PID.ToString()+"'"); Response.Write(",Note:'"+info.Note+"'},"); } Response.Write("]}"); } } }
这里面我们建立的是一个PartialView ,以便更好的加载到任何页面中。
我首先简要介绍一下 Controller 的内容;
public ActionResult NewsCatalogManager(); 完成页面的加载
public ActionResult NewCatalog(int PID,string CatalogName,string Note); 支持Ajax实现新分类的添加
public ActionResult EditCatalog(int ID,string Note); 支持Ajax对现有分类信息的修改
public ActionResult DeleteCatalog(int ID); 支持Ajax删除一个分类节点
public void LoadCatalog();支持Ajax提取全部分类信息;
我们可以看到除了第一个NewsCatalogManager()是系统加载使用的外,其余的全部采用Ajax的方式完成数据的管理;
下面我们看看也没事如何实现和完成信息调用的吧!
@modelIEnumerable<VonPortal.Web.Models.CatalogInfo> @{ Layout=null; } @Html.Import("header","zTreeStyle_css",@<linkrel="stylesheet"href="/content/zTreeStyle.css"type="text/css">) @Html.Import("header","zTreeDemo_css",@<linkrel="stylesheet"href="/content/Demo.css"type="text/css">) @Html.Import("header","ztree.1.js",@<scripttype="text/javascript"src="/scripts/jquery.ztree.core.js"></script>) @Html.Import("header","ztree.2.js",@<scripttype="text/javascript"src="/scripts/jquery.ztree.excheck.js"></script>) @Html.Import("header","ztree.3.js",@<scripttype="text/javascript"src="/scripts/jquery.ztree.exedit.js"></script>) <styletype="text/css"> .ztreelispan.button.add{ margin-left:2px; margin-right:-1px; background-position:-144px0; vertical-align:top; *vertical-align:middle; } </style> <divclass="content_wrap"> <ulid="tree"class="ztree"style="width:260px;overflow:auto;"></ul> </div> <inputid="catalogID"type="hidden"/> <divclass="input-group"> <spanclass="input-group-addon">分类名称</span><inputid="catalogName"type="text"class="form-control"placeholder="分类名称"/> </div> <textareaid="catalogNote"type="text"class="form-control"placeholder="分类说明"></textarea> <buttontype="button"class="btnbtn-info"onclick="addNode($('#catalogName').val(),$('#catalogNote').val())">添加同级</button> <buttontype="button"class="btnbtn-info"onclick="addChild($('#catalogName').val(),$('#catalogNote').val())">添加下级</button> <buttontype="button"class="btnbtn-info"onclick="editNode($('#catalogName').val(),$('#catalogNote').val())">修改本级</button> <scripttype="text/javascript"> varsetting={ view:{dblClickExpand:false,showLine:true,selectedMulti:false,selectedMulti:false},data:{key:{name:"CatalogName"},simpleData:{enable:true,idKey:"ID",pIdKey:"PID",rootPId:0}},edit:{ enable:true,editNameSelectAll:true,showRemoveBtn:function(treeId,treeNode){return!treeNode.isParent;},removeTitle:"删除节点",showRenameBtn:true,renameTitle:"修改节点" },callback:{ beforeRemove:function(treeId,treeNode){ varzTree=$.fn.zTree.getZTreeObj("tree"); zTree.selectNode(treeNode); returnconfirm("确认删除节点--"+treeNode.name+"吗?"); },onRemove:function(e,treeId,treeNode){ $.ajax({ type:'POST',url:"News/DeleteCatalog",data:"ID="+treeNode.ID,dataType:'json',cache:false,success:function(data){returntrue;} }); },beforeRename:function(e,treeNode,isCancel){ $.ajax({ type:'POST',url:"News/EditCatalog",data:{"ID":treeId.ID,"CatalogName":treeNode,"Note":treeId.Note},onClick:function(event,treeNode){ varzTree=$.fn.zTree.getZTreeObj("tree"); zTree.selectNode(treeNode); $("#catalogID").val(treeNode.ID); $("#catalogName").val(treeNode.CatalogName); $("#catalogNote").val(treeNode.Note); },onDrap:function(event,treeNodes,targetNode,moveType){ alert(treeNodes.length+","+(targetNode?(targetNode.tId+","+targetNode.name):"isRoot")); } } }; $(function(){ $.get("News/LoadCatalog",function(response){ vardata=eval(response); $.fn.zTree.init($("#tree"),setting,data); }); }); functionaddNode(name,note) { varzTree=$.fn.zTree.getZTreeObj("tree"); varnodes=zTree.getSelectedNodes(); varpid=0; if(nodes.length>0)pid=nodes[0].PID; $.ajax({ type:'POST',url:"News/NewCatalog",data:{"PID":pid,"CatalogName":$("#catalogName").val(),"Note":$("#catalogNote").val()},success:function(data){ if(pid>0)zTree.addNodes(nodes[0].getParentNode(),-1,{ID:data.html,CatalogName:$("#catalogName").val(),PID:pid,Note:$("#catalogNote").val()}); elsezTree.addNodes(null,Note:$("#catalogNote").val()}); } }); } functionaddChild(name,note){ varzTree=$.fn.zTree.getZTreeObj("tree"); varnodes=zTree.getSelectedNodes(); if(nodes.length<1)alert("尚未选中节点"); $.ajax({ type:'POST',data:{"PID":nodes[0].ID,success:function(data){ zTree.addNodes(nodes[0],PID:nodes[0].ID,Note:$("#catalogNote").val()}); } }); } functioneditNode(name,data:{"ID":nodes[0].ID,success:function(data){ nodes[0].CatalogName=$("#catalogName").val(); nodes[0].Note=$("#catalogNote").val(); zTree.updateNode(nodes[0]); } }); } </script>
首先我们来分析一下 zTree 的配置信息,也就是setting
varsetting={ view:{dblClickExpand:false,"+targetNode.name):"isRoot")); } } };
重点是 Data 和 callback,在data里面我们指定了我们CatalogInfo的展示方式,也就是说zTree支持我们自定义数据的展示,我们在这里指定了,我们的展示数据和节点数据的内容:
data: { key: { name: "CatalogName" },simpleData: { enable: true,idKey: "ID",pIdKey: "PID",rootPId: 0 } },
在callback中我们定义了所有zTree的操作交互内容:我们主要定义了以下几个相应事件:
最后为了完成分类信息的添加和全部信息的修改,我们建立了一个信息编辑区域:
<inputid="catalogID"type="hidden"/> <divclass="input-group"> <spanclass="input-group-addon">分类名称</span><inputid="catalogName"type="text"class="form-control"placeholder="分类名称"/> </div> <textareaid="catalogNote"type="text"class="form-control"placeholder="分类说明"></textarea> <buttontype="button"class="btnbtn-info"onclick="addNode($('#catalogName').val(),$('#catalogNote').val())">修改本级</button>
在这里面我们可以完成信息的同级添加和下级添加,同样,这是通过ajax完成的,对应的javascript函数是
这样我们就完成了zTree的主要基本操作和控制了。
看看我实现的界面效果:
呵呵,还可以吧!
原文链接:https://www.f2er.com/ajax/162250.html