无限分级和tree结构数据增删改【附DEMO下载】
阅读目录
•无限分级
•jstree插件
•demo
•创建region实体
•满足jstree插件的数据对象dto
•数据转换
•初始化获取转换后的数据
•前台数据加载
•其他操作
•通过按钮来操作增删改
无限分级
很多时候我们不确定等级关系的层级,这个时候就需要用到无限分级了。
说到无限分级,又要扯到递归调用了。(据说频繁递归是很耗性能的),在此我们需要先设计好表机构,用来存储无限分级的数据。当然,以下都是自己捣鼓的结果,非标准。谁有更好的设计望不吝啬赐教。
说来其实也简单,就是一个id和父id的关系。
以此类推,id需要是唯一的,parenid需要是id列里面存在即可。这样我们就实现无限分级了,如果再加一列sort排序就更完美了。
jstree插件
官方地址:
为什么要用这个插件?因为有方便的api给我们做数据绑定,且支持节点拖动来实现增删改,个人觉得这个功能挺强大的。
demo
下面我们来基于jstree插件来实现无限分级数据操作。以区域数据操作为例,用code first的方式来编写demo代码。
创建region实体
为了配合插件自动生成的节点id,我们这里使用的node和parentnode来存储上下级关系(而不是上面说的id和parentid,但是实际效果是一样的)。
/// <summary> /// 区域 /// </summary> public class region { /// <summary> /// 主键id /// </summary> public int id { get; set; } /// <summary> /// 名称 /// </summary> public string name { get; set; } /// <summary> /// 节点 /// </summary> public string node { get; set; } /// <summary> /// 父节点 /// </summary> public string parentnode { get; set; } }
满足jstree插件的数据对象dto
为了适应jstree插件的数据要求,我们需要把上面的数据转换成树状的数据对象。
/// <summary> /// dto /// </summary> public class regionstreeoutput { /// <summary> /// id /// </summary> public int regionsid { get; set; } /// <summary> /// tree显示文本(对应region的name) /// </summary> public string text { get; set; } /// <summary> /// tree的id(对应node) /// </summary> public string id { get; set; } /// <summary> /// 子节点数据(此属性就体现的数据的层级关系) /// </summary> public list<regionstreeoutput> children { get; set; } }
数据转换
#region getregiontree 初始化数据获取 的辅助方法 public regionstreeoutput loadregions(string id, list<region> inregions, regionstreeoutput outregions) { list<region> regions = inregions.where(t => t.parentnode == id).tolist(); if (outregions == null)//加载父节点 { outregions = totreedata(regions[0]); loadregions(outregions.id, inregions, outregions); } else//加载子节点 { outregions.children = totreesdata(regions); if (regions.count > 0) { for (int i = 0; i < regions.count; i++) { loadregions(regions[i].node, inregions, outregions.children[i]);//递归调用 } } } return outregions; } public regionstreeoutput totreedata(region region) { var treedata = new regionstreeoutput(); treedata.id = region.node; treedata.text = region.name; treedata.regionsid = region.id; return treedata; } public list<regionstreeoutput> totreesdata(list<region> listregion) { var regions = new list<regionstreeoutput>(); for (int i = 0; i < listregion.count; i++) { regions.add(totreedata(listregion[i])); } return regions; } #endregion
初始化获取转换后的数据
/// <summary> /// 初始化数据获取 /// </summary> /// <returns></returns> public jsonresult getresultdata() { treedbcontext db = new treedbcontext(); var regions = db.regions.where(t => true).tolist(); var regionobj = loadregions("-1", regions, null); return json(regionobj); }
以上后台的数据差不多就完成了。
前台数据加载
$(function () { $.post("/home/getresultdata", null, function (sdata) { treeobj = $('#jstree_demo').jstree({ //, "checkbox" 'plugins': ["contextmenu", "dnd", "search", "state", "types", "wholerow"], 'core': { "animation": 0, "check_callback": true, 'force_text': true, "themes": { "stripes": true }, 'data': sdata }, "types": { "default": { "icon": "fa fa-folder icon-state-warning icon-lg" }, "file": { "icon": "fa fa-file icon-state-warning icon-lg" } }, "contextmenu": { select_node: false, show_at_node: true, items: function (o, cb) { //因为这里我们之后需要定义多个项,所以通过对象的方式返回 var actions = {}; //添加一个"新增"右键菜单 actions.create = {//这里的create其实阔以随意命名,关键是里面的 这里面的 action回调方法 "separator_before": false,//create这一项在分割线之前 "separator_after": true,//create这一项在分割线之后 "_disabled": false, //false表示 create 这一项可以使用; true表示不能使用 "label": "新增", //create这一项的名称 可自定义 "action": function (data) { //点击create这一项触发该方法,这理还是蛮有用的 var inst = $.jstree.reference(data.reference), obj = inst.get_node(data.reference);//获得当前节点,可以拿到当前节点所有属性 //新加节点,以下三行代码注释掉就不会添加节点 inst.create_node(obj, {}, "last", function (new_node) { settimeout(function () { inst.edit(new_node); }, 0);//新加节点后触发 重命名方法,即 创建节点完成后可以立即重命名节点 }); } }; if (o.id != "0001")//屏蔽对根节点的操作 “0001”改成根节点对应的真是id { //添加一个"重命名"右键菜单 actions.rename = { "separator_before": false, "separator_after": false, "_disabled": false, //(this.check("rename_node", data.reference, this.get_parent(data.reference), "")), "label": "重命名", "action": function (data) { var inst = $.jstree.reference(data.reference), obj = inst.get_node(data.reference); inst.edit(obj); } } //添加一个"删除"右键菜单 actions.delete = { "separator_before": false, "icon": false, "separator_after": false, "_disabled": false, //(this.check("delete_node", data.reference, this.get_parent(data.reference), "")), "label": "删除", "action": function (data) { var inst = $.jstree.reference(data.reference), obj = inst.get_node(data.reference); if (inst.is_selected(obj)) { inst.delete_node(inst.get_selected()); } else { inst.delete_node(obj); } } }; } return actions;//返回右键菜单项 } }, }); }); });
其他操作
//删除节点 $('#jstree_demo').on('delete_node.jstree', function (e, data) { var id = data.node.original.regionsid; $.ajax({ type: "get", url: "/home/deleteregion?id=" + id, success: function (sdata) { } }); }); //移动节点 $('#jstree_demo').on('move_node.jstree', function (e, data) { saveregions(data); }); //修改名 $('#jstree_demo').on('rename_node.jstree', function (e, data) { saveregions(data); }); //保存 function saveregions(data) { var id = data.node.original.regionsid; var name = data.node.text;//修改后的name //var oldname = data.old;//原name //var pnode = $('#jstree_demo').jstree().get_node(data.node.parent).original.regionsid; var josndata = { "id": id, "node": data.node.id, "parentnode": data.node.parent, "name": name }; $.ajax({ url: "/home/saveregions", data: josndata, success: function (sdata) { data.node.original.regionsid = sdata; data.node.state.opened = false;//是否展开 } }); }
当然,记得修改或是删除要取regionsid这个对应后台实体的id。
通过按钮来操作增删改
function createtree() { var ref = $('#jstree_demo').jstree(true), sel = ref.get_selected(); if (!sel.length) { return false; } sel = sel[0]; sel = ref.create_node(sel, { "type": "file" }); if (sel) { ref.edit(sel); } }; function renametree() { var ref = $('#jstree_demo').jstree(true), sel = ref.get_selected(); if (!sel.length) { return false; } sel = sel[0]; ref.edit(sel, function () { }); }; function deletetree() { var ref = $('#jstree_demo').jstree(true), sel = ref.get_selected(); if (!sel.length) { return false; } ref.delete_node(sel); };
如果大家想了解详情请下载源码:
http://xiazai.jb51.net/201605/yuanma/treedemo(jb51.net).rar
关于无限分级和tree结构数据增删改的相关知识就给大家介绍到这里,希望对大家有所帮助!