摘要:近期項目用到大量的樹結構,比如目錄樹文章標記動態生成樹結構,實現的過程是基于的框架,結合數據驅動應用遞歸函數實現數據結構的增刪改查一切思緒的來源,結合官方提供的樹形圖實例,可以輕松實現自定義開源樹結構,上優秀的開源插件我都看過,都是基于樹形
近期項目用到大量的樹結構,比如目錄樹、文章標記動態生成樹結構,實現的過程是基于vue的框架,結合vue數據驅動應用遞歸函數實現數據結構的增刪改查
一切思緒的來源,結合vue官方提供的樹形圖實例,可以輕松實現自定義開源樹結構,github上優秀的開源插件我都看過,都是基于樹形結構實現的
vue樹形視圖
以上是定義模板以及在頁面中應用,首先遍歷treedata把單項傳入子組件也就是本例的模板,下面js文件
// 定義子組件 Vue.component("item", { template: "#item-template", props: { model: Object, }, data: function () { return { openr:false, } }, computed: { isFolder: function () { return this.model.children && this.model.children.length; } }, methods: { //獲取選中節點數據 toggle(model){ if (this.isFolder) { vm.$set(model, "isExpand", !model.isExpand); } }, //獲取選中節點數據以及設置選中狀態 handle (item) { this.emitHandle(item) console.log(item) var nodeId; if (event.path[0].id) { nodeId = event.path[0].id; } else if(event.path[1].id){ nodeId = event.path[1].id; } else{ nodeId = event.path[2].id; } setMouseMenu(nodeId,".treeMenu"); }, emitHandle (item) { this.$emit("handle", item) } } }) // 定義父組件 var vm = new Vue({ el: "#bookMarker", data: { templateName:"",//內容模板 associations:"",//癥狀關系 elements:"", //模板下elements數組 allIsExpand: true, dialogTit:"", //彈框的title getRangeText:"",//標引選中的文本 resultName:"",//彈框input值 elementId:"", elementType:"", orderNum:"", postArray:[], off:false, radio:"", scrollTop:0,//codemirror滾動條高度 height:"",//codemirror內容高度 oldContent:"",//子組件自定義title屬性數據 associationsElements:"", ariaHidden:true,//語義彈框顯隱控制 ztreeData:[],//ztree的數據列表 }, created(){ this.getMarkerList(); this.getTemplateInfo(); }, mounted(){ this.initView(); this.setCodeMenu(); setActiveClass(); $("body").click(()=>{ this.oldContent=""; }) setTreeFoundation(this.$refs.treebox, this.$refs.treeFoundation); }, watch:{ "ztreeData":{ handler: function(val, oldval) { this.$nextTick(() => { this.$refs.treeMenu.style.display="none" }) }, deep: true } }, methods:{ // 獲取選中節點 setSelectedNode(model){ this.off = true; var g=function(child){ child.forEach(function (item, index) { if (item.Selected==true) { vm.$set(item, "Selected", false) } var subChild = item.children; if(subChild!=null && subChild.length>0){ g(subChild); } }); } this.ztreeData.forEach(function (item, index) { if (item.Selected==true) { vm.$set(item, "Selected", false) } var child =item.children; g(child); }); vm.$set(model, "Selected", true) this.onCodemirrorLight(model); }, getSelectedNode () { var roots = []; var model; this.ztreeData.forEach(function(item,index){ if(item.parentId ==0){ roots.push(item); } }); var g=function(child){ child.forEach(function (item, index) { if (item.Selected==true) { model=item; return; } var subChild = item.children; if(subChild!=null && subChild.length>0){ g(subChild); } }); } roots.forEach(function (item, index) { if (item.Selected==true) { model=item; return; } var child =item.children; g(child); }); return model; }, //獲取模態框title getDialogTitle: function(item){ this.dialogTit=""; this.dialogChilTit=""; if (this.getRangeText) { this.dialogTit = item.elementName||item.associationName; this.orderNum=item.orderNum; this.elementId=item.elementId; this.elementType=item.elementType; event.target.dataset.toggle="modal"; } else{ event.target.dataset.toggle=""; } }, //全部折疊 allClose(){ this.updateAllIsExpand(false); this.allIsExpand = true; }, //全部展開 allOpen(){ this.updateAllIsExpand(true); this.allIsExpand = false; }, //刪除節點 removeNode(){ var item = this.getSelectedNode() var index=0; if (item.parentId==0) { for(var i in this.ztreeData){ if(this.ztreeData[i]["id"]==item.id){ index=i; break; } } this.ztreeData.splice(index,1); } else{ var parentItem = this.getNodeItem(item.parentId).children; parentItem.splice(parentItem.indexOf(item), 1); } //重置選中狀態 $("div").removeClass("activeClass"); }, //codemirror鼠標右鍵菜單 setCodeMenu(){ var doc = document.getElementById("box_fr"); var forRight = $(".codeMenu") var _this = this; doc.oncontextmenu=function(event){//關鍵點 var event=event||window.event; if (_this.getRangeText) { forRight.get(0).style.display="block"; forRight.get(0).style.left=event.pageX+"px"; forRight.get(0).style.top=event.pageY+"px"; return false; } }; doc.onclick=function(e){ forRight.get(0).style.display= "none"; e.preventDefault(); }; }, //設置語義關聯 setAssociation(item){ this.resultName = item.elementName; this.Submit(); }, //全部展開收起公共方法 updateAllIsExpand(boolean){ var g=function(child,expand){ child.forEach(function (item, index) { var childisExpand; childisExpand = vm.$set(item, "isExpand", expand); var subChild = item.children; if(subChild!=null && subChild.length>0){ g(subChild,childisExpand); } }); } if (this.off==true) { var item = this.getSelectedNode() if (item) { var expand; expand = vm.$set(item, "isExpand", boolean); var child =item.children; g(child,expand); } } else{ this.ztreeData.forEach((ite)=>{ var expand; expand = vm.$set(ite, "isExpand", boolean); var child =ite.children; g(child,expand); }) } }, //獲取結構模板信息 getTemplateInfo: function(){ this.$ajax({ method: "post", url: "/marker/api/getTemplateInfo", data: { taskId:19 } }).then((res)=>{ if (res.data.code === 1000) { this.elements = res.data.data.elements; this.associations = res.data.data.associations; this.templateName = res.data.data.templateName; res.data.data.associations.forEach((item)=>{ this.associationsElements = item.elements }) console.log(res.data.data,"getTemplete"); } },(err)=>{ console.log(err); }) }, //獲取根節點id getRoot(){ this.off=false; }, //獲取樹結構列表 getMarkerList: function(){ this.$ajax({ method: "post", url: "/marker/api/getMarkerList", data: { taskId:19 } }).then((res)=>{ if (res.data.code === 1000) { if (res.data.data==null) {return}; this.ztreeData = res.data.data; var roots = []; this.ztreeData.forEach(function(item,index){ if(item.parentId ==0){ roots.push(item); } }); var g=function(child,level,isExpand,Selected){ var childLevel=level+1; var childisExpand = isExpand; var childSelected = Selected; child.forEach(function (item, index) { item.level=childLevel; vm.$set(item, "isExpand", childisExpand) vm.$set(item, "Selected", childSelected) var subChild = item.children; if(subChild!=null && subChild.length>0){ g(subChild,childLevel,childisExpand,childSelected); } }); } roots.forEach(function (item, index) { item.level= 0 ; vm.$set(item, "isExpand", false) vm.$set(item, "Selected", false) var child =item.children; g(child, item.level, item.isExpand, item.Selected); }); console.log(res.data,"getMarkerList"); } },(err)=>{ console.log(err); }) }, //通過resultId獲取item getNodeItem:function(resultId){ var resultItem = {}; var g=function(child,resultId){ child.forEach(function (item) { if (item.resultId==resultId) { resultItem = item; return; } var subChild = item.children; if(subChild!=null && subChild.length>0){ g(subChild,resultId); } }); } this.ztreeData.forEach((item)=>{ var child = item.children; if (item.resultId==resultId) { resultItem = item; return; } g(child, resultId); }) return resultItem; }, //codemirror滾動到頂部 goDocUp(){ this.CodeMirrorEditor.scrollTo(0,0) }, //codemirror滾動到底部 goDocDown(){ var initH = 5000 this.CodeMirrorEditor.scrollTo(0,this.height+ initH+ this.scrollTop) }, //codemirror顯示高亮 onCodemirrorLight:function(item){ if (!item) {return}; var startPos = item.startPos, endPos = item.endPos, strat, end; //將返回_index轉為Pos對象 strat = this.posFromIndex(startPos-1); end = this.posFromIndex(endPos-1); //文本高亮 this.CodeMirrorEditor.setSelection(strat,end); // this.CodeMirrorEditor.scrollTo(0,item.scrollTop) // this.CodeMirrorEditor.setValue(model.oldContent) }, //提交用戶操作 Submit:function(){ var parentId,level,Selected,isExpand; if (this.off==true) { var item = this.getSelectedNode(); if (item) { parentId = item.resultId; level = item.level+1; Selected = item.Selected; isExpand = item.isExpand } } else{ parentId = 0; level = 0; Selected = false; isExpand = false; } if (!this.resultName) { alert("請填寫標題");return event.target.dataset.dismiss=""}; var _data = { taskId:19, parentId:parentId, startPos:this.postArray[0], endPos:this.postArray[1], resultName:this.resultName, elementId:this.elementId, elementType:this.elementType, orderNum:this.orderNum, oldContent:this.getRangeText, level:level, children:[], Selected:Selected, isExpand:isExpand, }; this.$ajax({ method: "post", url: "/marker/api/save", data: _data }).then((res)=>{ if (res.data.code === 1000) { $("#myModal").modal("hide") //結合接口返回設置_data數據 this.resultName = ""; this.allIsExpand = true; this.$refs.codeMenu.style.display="none"; _data.resultId = res.data.data; if(parentId == 0){ this.ztreeData.push(_data); // console.log(JSON.parse(JSON.stringify(this.ztreeData)),"追加以后ztreeData") } else{ item.children.push(_data); vm.$set(item, "isExpand", true); } console.log(JSON.parse(JSON.stringify(this.ztreeData)),"追加以后ztreeData"); } },(err)=>{ console.log(err); }) }, //用戶取消操作 Cancel:function(){ this.resultName=""; this.getRangeText=""; }, //初始化頁面結構以及數據 initView: function(){ //獲取右側文章 this.$ajax({ method: "post", url: "/marker/api/getFullText", data: { taskId:19 } }).then((res)=>{ if (res.data.code === 1000) { this.CodeMirrorEditor.setValue(res.data.data); } },(err)=>{ console.log(err); }) //初始化codemirror let myTextarea = document.getElementById("editor"); this.CodeMirrorEditor = CodeMirror.fromTextArea(myTextarea, { lineWrapping :true, styleActiveLine: true, foldGutter: true, styleSelectedText: true, mode: "text/javascript", matchBrackets: true, cursorScrollMargin:120,//光標上下預留額外空間 showCursorWhenSelecting: true, theme: "default", }); // 光標或選中(內容)事件 this.cursorActivity(); // 記錄內容改變事件 this.CodeMirrorEditor.on("change",(instance,changeObj)=>{ console.log("change",instance,changeObj) this.height = instance.doc.height; }); //記錄滾動事件 this.CodeMirrorEditor.on("scroll",(cm)=>{ this.scrollTop = cm.doc.scrollTop }); }, //設置resultName setResultName(event){ this.resultName = getSelectText(event); }, //根據Pos轉為數字下標 indexFromPos: function(Pos) { if(Pos.line < 0 || Pos.ch < 0) { return false; } var _index= Pos.ch+1; this.CodeMirrorEditor.eachLine(0, Pos.line, function(item){ _index+= item.text.length+1; }) return _index; }, //根據數字下標轉為Pos posFromIndex: function(_index) { var line = 0, ch; this.CodeMirrorEditor.eachLine(0, this.CodeMirrorEditor.lineCount(), function(item) { var textNum = item.text.length + 1; if(textNum > _index) { ch = _index; return true; } else{ _index -= textNum; ++line; } }); return({ line: line, ch: ch }) }, // 光標或選中(內容)事件 cursorActivity(){ this.CodeMirrorEditor.on("cursorActivity",(cm)=>{ var startObj = {}, endObj = {}, objArray = [], newObjArray = [], activeArray = []; //拖動鼠標開始位置結束位置,支持正反選 endObj.line = cm.getCursor("head").line; endObj.ch = cm.getCursor("head").ch; startObj.line = cm.getCursor("anchor").line; startObj.ch = cm.getCursor("anchor").ch; objArray.push(startObj,endObj); // 保存開始結束位置數字下標 newObjArray.push(this.indexFromPos(startObj),this.indexFromPos(endObj)); newObjArray.sort((x,y)=>{ return x-y; }) this.postArray = newObjArray; //根據Pos獲取選中文本 sortPosArray(objArray); this.getRangeText = cm.getRange(objArray[0],objArray[1]); }); } } }); /*** ***dom.js*** ***/ //設置選中active狀態 function setActiveClass(){ $(document).on("click",".menuLi>div", function(){ $(".treeFoundation").removeClass("activeClass") $("div").removeClass("activeClass"); $(this).addClass("activeClass"); }) $(document).on("click",".item>div", function(){ $("div").removeClass("activeClass"); $(".treeFoundation").removeClass("activeClass") $(this).addClass("activeClass"); }) $(".treeFoundation").click(function(){ $(this).addClass("activeClass") $(".sidebar-menu div").removeClass("activeClass"); }) }; //鼠標右鍵菜單 function setMouseMenu(target, cursorClass){ if (!target||target==null||!cursorClass) {return} var doc = document.getElementById(target); var forRight = $(cursorClass) doc.oncontextmenu=function(event){//關鍵點 var event=event||window.event; forRight.get(0).style.display="block"; forRight.get(0).style.left=event.pageX+"px"; forRight.get(0).style.top=event.pageY+"px"; return false; }; doc.onclick=function(e){ forRight.get(0).style.display="none"; e.preventDefault(); }; }; //根據codemirror對Pos下標排序 function sortPosArray(PosArray){ PosArray.sort((c1, c2) => { if (c1.ch == c2.ch) { return c1.line - c2.line } else if (c1.line>c2.line) { return c1.line - c2.line } else if(c1.line{ if (parent.scrollTop>=90) { child.style.position="fixed"; child.style.width=47.5+"%"; child.style.zIndex=2; child.style.boxShadow="0px 1px 1px #d9d9d9"; } else{ child.style.position="static"; child.style.width="auto"; child.style.boxShadow="none"; } }, false) };
var roots = []; this.ztreeData.forEach(function(item,index){ if(item.parentId ==0){ roots.push(item); } }); var g=function(child,level,isExpand,Selected){ var childLevel=level+1; var childisExpand = isExpand; var childSelected = Selected; child.forEach(function (item, index) { item.level=childLevel; vm.$set(item, "isExpand", childisExpand) vm.$set(item, "Selected", childSelected) var subChild = item.children; if(subChild!=null && subChild.length>0){ g(subChild,childLevel,childisExpand,childSelected); } }); } roots.forEach(function (item, index) { item.level= 0 ; vm.$set(item, "isExpand", false) vm.$set(item, "Selected", false) var child =item.children; g(child, item.level, item.isExpand, item.Selected); });
以上是遞歸函數的應用,很實用可以解決很多后端的問題
另外說一嘴,解決遞歸組件事件傳遞的方法有很多,比如事件車,本實例之初也用到了事件車,因為代碼設計的要求換了另一種實現的方式,心細的朋友多看幾遍就會發現
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/98210.html
摘要:像剛才的這幅圖,就是二叉搜索樹。而我們本文要學習的內容,就是如何寫一個二叉搜索樹。但在二叉搜索樹中,我們把節點成為鍵,這是術語。前端路漫漫,且行且歌的前端樂園原文鏈接寒假前端學習學習數據結構與算法四二叉搜索樹 本系列的第一篇文章: 學習JavaScript數據結構與算法(一),棧與隊列第二篇文章:學習JavaScript數據結構與算法(二):鏈表第三篇文章:學習JavaScript數據...
摘要:詢問權威的服務器域名服務器會繼續檢查請求的下一部分,并將查詢指向負責此特定域名的服務器這些權威的服務器將負責了解關于特定域的所有信息,并將信息存儲在記錄。 面試經典題——URL加載 一、涉及基本知識點: 1. 計算機網絡 五層因特爾協議棧: 應用層(dns、http):DNS解析成IP并完成http請求發送; 傳輸層(tcp、udp):三次握手四次揮手模式建立tcp連接; 網絡層...
摘要:詢問權威的服務器域名服務器會繼續檢查請求的下一部分,并將查詢指向負責此特定域名的服務器這些權威的服務器將負責了解關于特定域的所有信息,并將信息存儲在記錄。 面試經典題——URL加載 一、涉及基本知識點: 1. 計算機網絡 五層因特爾協議棧: 應用層(dns、http):DNS解析成IP并完成http請求發送; 傳輸層(tcp、udp):三次握手四次揮手模式建立tcp連接; 網絡層...
閱讀 1642·2023-04-25 18:19
閱讀 2085·2021-10-26 09:48
閱讀 1092·2021-10-09 09:44
閱讀 1741·2021-09-09 11:35
閱讀 3034·2019-08-30 15:54
閱讀 2031·2019-08-30 11:26
閱讀 2295·2019-08-29 17:06
閱讀 892·2019-08-29 16:38