资讯专栏INFORMATION COLUMN

Javascript js递归函数 树结构

junbaor / 536人阅读

摘要:近期项目用到大量的树结构,比如目录树文章标记动态生成树结构,实现的过程是基于的框架,结合数据驱动应用递归函数实现数据结构的增删改查一切思绪的来源,结合官方提供的树形图实例,可以轻松实现自定义开源树结构,上优秀的开源插件我都看过,都是基于树形

近期项目用到大量的树结构,比如目录树、文章标记动态生成树结构,实现的过程是基于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);
              });
以上是递归函数的应用,很实用可以解决很多后端的问题

另外说一嘴,解决递归组件事件传递的方法有很多,比如事件车,本实例之初也用到了事件车,因为代码设计的要求换了另一种实现的方式,心细的朋友多看几遍就会发现

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/98210.html

相关文章

  • 学习JavaScript数据结构与算法(四):二叉搜索

    摘要:像刚才的这幅图,就是二叉搜索树。而我们本文要学习的内容,就是如何写一个二叉搜索树。但在二叉搜索树中,我们把节点成为键,这是术语。前端路漫漫,且行且歌的前端乐园原文链接寒假前端学习学习数据结构与算法四二叉搜索树 本系列的第一篇文章: 学习JavaScript数据结构与算法(一),栈与队列第二篇文章:学习JavaScript数据结构与算法(二):链表第三篇文章:学习JavaScript数据...

    ingood 评论0 收藏0
  • 一个页面从输入URL到加载显示完成,发生了什么?

    摘要:询问权威的服务器域名服务器会继续检查请求的下一部分,并将查询指向负责此特定域名的服务器这些权威的服务器将负责了解关于特定域的所有信息,并将信息存储在记录。 面试经典题——URL加载 一、涉及基本知识点: 1. 计算机网络 五层因特尔协议栈: 应用层(dns、http):DNS解析成IP并完成http请求发送; 传输层(tcp、udp):三次握手四次挥手模式建立tcp连接; 网络层...

    NervosNetwork 评论0 收藏0
  • 一个页面从输入URL到加载显示完成,发生了什么?

    摘要:询问权威的服务器域名服务器会继续检查请求的下一部分,并将查询指向负责此特定域名的服务器这些权威的服务器将负责了解关于特定域的所有信息,并将信息存储在记录。 面试经典题——URL加载 一、涉及基本知识点: 1. 计算机网络 五层因特尔协议栈: 应用层(dns、http):DNS解析成IP并完成http请求发送; 传输层(tcp、udp):三次握手四次挥手模式建立tcp连接; 网络层...

    nanchen2251 评论0 收藏0

发表评论

0条评论

junbaor

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<