zTree -- jQuery 树插件
https://www.treejs.cn/v3/main.php#_zTreeInfo 官方文档,demo和api
https://www.cnblogs.com/fonour/p/zTree.html
https://www.cnblogs.com/longlyseul/p/12111143.html 通俗容易理解
http://127.0.0.1:8000/appsmarts/home/
<script type="text/javascript" src="{% static 'ztree/js/jquery.ztree.core.js' %}"></script> 只能做显示
<script type="text/javascript" src="{% static 'ztree/js/jquery.ztree.all.js' %}"></script> 可以复选、编辑等
API:
@router.get('/treedict') def list_person(request): dictdata=Jg.objects.values('p_code','parent_code','short_name') return list(dictdata)
相关tree.html
<!DOCTYPE html> {% load static %} <HTML> <HEAD> <TITLE> ZTREE DEMO </TITLE> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link href="{% static 'ztree/css/zTreeStyle/zTreeStyle.css' %}" rel="stylesheet" /> <link href="{% static 'ztree/css/demo.css' %}" rel="stylesheet" /> <script type="text/javascript" src="{% static 'ztree/js/jquery-1.4.4.min.js' %}"></script> <script type="text/javascript" src="{% static 'ztree/js/jquery.ztree.core.js' %}"></script> <SCRIPT LANGUAGE="JavaScript"> var zTreeObj; // zTree 的参数配置,深入使用请参考 API 文档(setting 配置详解) var setting = { view: { selectedMulti: true, //设置是否能够同时选中多个节点 }, data: { simpleData: { enable: true, idKey: "p_code", pIdKey: "parent_code", //rootPId: 0 }, key: { name: "short_name",//name是共通化属性,不是simpleData仅有的,所以与idKey不同,单独用key设置 } }, check:{ enable: true //设置是否显示checkbox复选框 }, callback: { beforeClick: beforeClick, onClick: onClick } }; // zTree 的数据属性,深入使用请参考 API 文档(zTreeNode 节点数据详解) var zNodes =[ { id:1, pId:0, name:"普通的父节点", t:"我很普通,随便点我吧", open:true}, { id:11, pId:1, name:"叶子节点 - 1", t:"我很普通,随便点我吧"}, { id:2, pId:0, name:"NB的父节点", t:"点我可以,但是不能点我的子节点,有本事点一个你试试看?", open:true}, { id:21, pId:2, name:"叶子节点2 - 1", t:"你哪个单位的?敢随便点我?小心点儿..", click:false}, { id:23, pId:2, name:"叶子节点2 - 3", t:"好歹我也是个领导,别普通群众就来点击我..", click:false}, { id:3, pId:0, name:"郁闷的父节点", t:"别点我,我好害怕...我的子节点随便点吧...", open:true, click:false }, { id:31, pId:3, name:"叶子节点3 - 1", t:"唉,随便点我吧"}, ]; var log,className = "dark"; function beforeClick(treeId, treeNode, clickFlag) { return (treeNode.click != false); } function onClick(event, treeId, treeNode, clickFlag) { if (treeNode.isParent) //如果不是叶子结点,结束 return; showLog( treeNode.short_name+' '+ treeNode.p_code); }; 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]); } } $(document).ready(function () { //这是用var zNodes的假设数据启动tree //zTreeObj = $.fn.zTree.init($("#treeDemo"), setting, zNodes); //这是用ajax ipi调用数据启用tree $.ajax({ type: "Get", url: "http://127.0.0.1:8000/api/api3/treedict", //ajax请求地址 success: function (data) { $.fn.zTree.init($("#treeDemo"), setting, data); //加载数据 }, }); $(".btn1").click(function(){ $("p").slideToggle(); }); }); //below three is same //$(document).ready(function) //$().ready(function) //$(function) </SCRIPT> </HEAD> <BODY> <div> <ul class="list"> <li><p><span class="highlight_red">请尝试按下 <b>Ctrl</b> 或 <b>Cmd</b> 键进行 多节点选择 和 取消选择</span><br/> click log:<br/> <ul id="log" class="log"></ul></p> </li> </ul> <div id="rMenu" style="z-index:100;"> </div> <ul id="treeDemo" class="ztree"></ul> </div> </BODY> </HTML>
关键说明:
1、默认提供的数据是 id, pId,name,如
{ id:23, pId:2, name:"叶子节点2 - 3", t:"好歹我也是个领导,别普通群众就来点击我..", click:false}, { id:3, pId:0, name:"郁闷的父节点", t:"别点我,我好害怕...我的子节点随便点吧...", open:true, click:false }, { id:31, pId:3, name:"叶子节点3 - 1", t:"唉,随便点我吧"},
如果api提供的是key name不同,则可以通过setting{data{} }的设定,把id,pId,name变成api 的相关key,参考上述 p_code, parent_code,short_name的例子
2、data中,click:false 的用途: 在function beforeClick函数中,限制onclick的相应
3、
可以对节点crud的tree的例子
<!DOCTYPE html> {% load static %} <HTML> <HEAD> <TITLE> ZTREE DEMO </TITLE> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link href="{% static 'ztree/css/zTreeStyle/zTreeStyle.css' %}" rel="stylesheet"/> <link href="{% static 'ztree/css/demo.css' %}" rel="stylesheet"/> // <script type="text/javascript" src="{% static 'ztree/js/jquery-1.4.4.min.js' %}"></script> <script src="{% static 'js/jquery-3.3.1.min.js' %}"></script> <script type="text/javascript" src="{% static 'ztree/js/jquery.ztree.all.js' %}"></script> <SCRIPT LANGUAGE="JavaScript"> var zTreeObj; // zTree 的参数配置,深入使用请参考 API 文档(setting 配置详解) var setting = { view: { selectedMulti: true, //设置是否能够同时选中多个节点 }, data: { simpleData: { enable: true } }, check: { enable: false//true //设置是否显示checkbox复选框 }, callback: { //onRightClick: OnRightClick, beforeClick: beforeClick, onClick: onClick, beforeRename: beforeRename, } }; // zTree 的数据属性,深入使用请参考 API 文档(zTreeNode 节点数据详解) var zNodes = [ {id: 1, pId: 0, name: "普通的父节点", t: "我很普通,随便点我吧", open: true}, {id: 11, pId: 1, name: "叶子节点 - 1", t: "我很普通,随便点我吧"}, {id: 2, pId: 0, name: "NB的父节点", t: "点我可以,但是不能点我的子节点,有本事点一个你试试看?", open: true}, {id: 21, pId: 2, name: "叶子节点2 - 1", t: "你哪个单位的?敢随便点我?小心点儿..", click: false}, {id: 23, pId: 2, name: "叶子节点2 - 3", t: "好歹我也是个领导,别普通群众就来点击我..", click: false}, {id: 3, pId: 0, name: "郁闷的父节点", t: "别点我,我好害怕...我的子节点随便点吧...", open: true, click: false}, {id: 31, pId: 3, name: "叶子节点3 - 1", t: "唉,随便点我吧"}, ]; var log, className = "dark"; function beforeClick(treeId, treeNode, clickFlag) { return (treeNode.click != false); } function onClick(event, treeId, treeNode, clickFlag) { if (treeNode.isParent) //如果不是叶子结点,结束 return; showLog(treeNode.name + ' ' + treeNode.id); }; 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 addTreeNode() { var zTree = $.fn.zTree.getZTreeObj("treeDemo"); var newNode = { name: name }; if (zTree.getSelectedNodes()[0]) { newNode.checked = zTree.getSelectedNodes()[0].checked; newNode.pid = zTree.getSelectedNodes()[0].id; zTree.addNodes(zTree.getSelectedNodes()[0], newNode); } else { zTree.addNodes(null, newNode); } var node = zTree.getNodeByParam("name", name, null); //得到新增加的节点 zTree.selectNode(node); //选中新增加的节点 zTree.editName(node); //让新增加的节点处于编辑状态 } //编辑节点 function editTreeNode() { var zTree = $.fn.zTree.getZTreeObj("treeDemo"); var nodes = zTree.getSelectedNodes(); //得到选中节点集合 if (nodes && nodes.length > 0) { var parent = nodes[0].getParentNode(); //得到选中节点的父节点 if (parent) { nodes[0].pid = parent.id; //如果选中节点父节点存在,将当前结点的pid属性值设置为父节点的id } zTree.editName(nodes[0]); //让选中节点处于编辑状态 } }; //刷新 function refreshTreeNode() { var zTree = $.fn.zTree.getZTreeObj("treeDemo"); zTree.refresh(); }; function removeTreeNode() { var zTree = $.fn.zTree.getZTreeObj("treeDemo"); var nodes = zTree.getSelectedNodes(); if (nodes && nodes.length > 0) { if (nodes[0].children && nodes[0].children.length > 0) { alert("包含下级,无法删除。"); } else { if (confirm("该操作会将关联数据同步删除,是否确认删除?") == true) { mydata = {"id": Number(nodes[0].id)}; console.log(mydata); $.ajax({ url: "/api/apitree/post_del",//数据入库 method: "POST", data: JSON.stringify(mydata), success: function (data) { if (data.result == "Success") { zTree.removeNode(nodes[0]); } else { alert("删除失败。"); } } }); } ; } } }; //新增和编辑后,节点编辑状态离开时触发事件 function beforeRename(treeId, treeNode, newName, isCancel) { if (newName.length == 0) { //节点名称判断 alert("不能为空。"); return false; } var mydata = {name: newName}; if (treeNode.id !== undefined) { mydata.id = treeNode.id } if (treeNode.pid !== undefined) { mydata.pid = treeNode.pid } console.log(mydata); $.ajax({ url: "/api/apitree/ins_or_upd",//数据入库 method: "POST", data: JSON.stringify(mydata), success: function (data) { if (data.result == "Faild") { layerAlert("保存失败。"); return false; } else { treeNode.id = data.result; //将返回的id赋值给当前结点 return true; } } }); }; $(document).ready(function () { //这是用var zNodes的假设数据启动tree zTreeObj = $.fn.zTree.init($("#treeDemo"), setting, zNodes); //这是用ajax ipi调用数据启用tree $.ajax({ type: "Get", url: "http://127.0.0.1:8000/api/api3/treedict_good", //ajax请求地址 success: function (data) { $.fn.zTree.init($("#treeDemo"), setting, data); //加载数据 }, }); $(".btn1").click(function () { $("p").slideToggle(); }); }); //below three is same //$(document).ready(function) //$().ready(function) //$(function) </SCRIPT> </HEAD> <BODY> <div> <ul class="list"> <li>利用 click 事件回调函数 可以进行各种其他的附加操作,这里简单演示如何监控此事件</li> <li><p><span class="highlight_red">请尝试按下 <b>Ctrl</b> 或 <b>Cmd</b> 键进行 多节点选择 和 取消选择</span><br/> click log:<br/> <ul id="log" class="log"></ul> </p> </li> </ul> <div id="rMenu" style="z-index:100;"> <ul> <li id="m_add" onclick="addTreeNode();">新增节点</li> <li id="m_del" onclick="removeTreeNode();">删除节点</li> <li id="m_edit" onclick="editTreeNode();">编辑节点</li> <!--<li id="m_reset" onclick="refreshTreeNode();">重置节点</li>--> </ul> </div> <ul id="treeDemo" class="ztree"></ul> </div> </BODY> </HTML>
以下是相关api,注意,本次的treeNode的节点属性用了默认的,数据必须是id,pId,name,可以增加(onclick=true or false)
@router.post("/ins_or_upd") def create_employee(request, payload: Jginout): print(payload) if payload.id: testjg = get_object_or_404(Testig, id=payload.id) for attr, value in payload.dict().items(): setattr(testjg, attr, value) testjg.save() else: payload.id=None testjg = Testig.objects.create(**payload.dict()) return {'result': testjg.id } @router.post("/post_del") def post_del_Testig(request, plyload: Jginout): print(request) print('ssss') print(plyload) print('aaaaa') person = get_object_or_404(Testig, id=plyload.id) person.delete() return {"result": 'Success'} #参数必须是pId ,注意大小写,pid不可以形成tree @router.get('/treedict_good') def treedict_good(request): dictdata=Testig.objects.annotate(pId=F('pid')).values('id','pId','name') return list(dictdata)