小程序無限級樹結構菜單擴展

無限級樹結構參考網址:https://blog.csdn.net/qq_42205731/article/details/92059227

我需要達到的效果是有幾個並列的根節點,並且根據配置顯示單選框或多選框,同時子節點是否展開也要收到控制

我對上面網址裏面的方法進行了改造,第一個根節點不顯示出來,然後第二級放多個節點,就實現多個並列根節點

代碼地址:https://github.com/zhangxianbin1/tree-miniprogram

效果圖:

tree.wxml頁面

<view class="treeClass">
  <view wx:if='{{model.id!=0}}'>
    <radio data-itemid='{{ model.id }}' data-parentnodes='{{ model.parentnodes }}' data-childnodes='{{ model.childnodes }}' data-siblingsnodes='{{model.siblingsnodes}}' data-rootnode='{{model.rootNode}}' data-type='radio' wx:if='{{ model.selectshow==1&&model.parentchooseway==0 }}'
      id="select{{model.index}}" bindtap='clickNode' checked="{{checked}}">
      <text>{{model.text}}</text>
    </radio>
    <checkbox data-itemid='{{ model.id }}' data-parentnodes='{{ model.parentnodes }}' data-childnodes='{{ model.childnodes }}' data-siblingsnodes='{{model.siblingsnodes}}' data-rootnode='{{model.rootNode}}' data-type='checkbox' wx:elif='{{ model.selectshow==1&&model.parentchooseway==1 }}'
      bindtap='clickNode' checked="{{checked}}">
      <text id="select{{model.index}}">{{model.text}}</text>
    </checkbox>
    <text bindtap='tapItem' data-itemid='{{ model.id }}' wx:else>{{ model.text }}</text>
  </view>
  <view style='padding-left: 50rpx;' wx:if='{{ isBranch }}' hidden='{{ !open }}'>
    <mytree wx:for='{{ model.nodes }}' wx:key='id' model='{{ item }}' id="component{{item.id}}"></mytree>
  </view>
</view>

tree.js頁面(增加點擊方法和刷新方法)

// pages/components/mytree/mytree.js
Component({
  properties: {
    model: Object,
  },

  data: {
    allopen: false,
    open: true,
    isBranch: false,
    checked: false
  },

  methods: {
    toggle: function(e) {
      if (this.data.isBranch) {
        this.setData({
          //open: !this.data.open,
        })
      }
    },

    tapItem: function(e) {
      var itemid = e.currentTarget.dataset.itemid;
      console.log('組件裏點擊的id: ' + itemid);
      this.triggerEvent('tapitem', {
        itemid: itemid
      }, {
        bubbles: true,
        composed: true
      });
    },
    clickNode: function(e) {
      var itemid = e.currentTarget.dataset.itemid;
      var parentnodes = e.currentTarget.dataset.parentnodes;
      var childnodes = e.currentTarget.dataset.childnodes;
      var siblingsnodes = e.currentTarget.dataset.siblingsnodes;
      var rootNode = e.currentTarget.dataset.rootnode;
      var type = e.currentTarget.dataset.type;
      console.log(e.currentTarget.dataset);
      this.triggerEvent('clickNode', {
        parentnodes: parentnodes,
        itemid: itemid,
        siblingsnodes: siblingsnodes,
        checked: !this.data.checked,
        open: !this.data.open,
        childnodes: childnodes,
        rootNode: rootNode,
        type: type
      }, {
        bubbles: true,
        composed: true
      })
    },
    reInit: function() {
      this.setData({
        isBranch: Boolean(this.data.model.nodes && this.data.model.nodes.length),
        open: Boolean(this.data.model.open),
        checked: Boolean(this.data.model.checked)
      });
      for (let i = 0; i < this.data.model.nodes.length; i++) {
        this.selectComponent('#component' + this.data.model.nodes[i].id).reInit();
      }
      //this.triggerEvent('reInit', {  }, { bubbles: true, composed: true })
    },
  },

  ready: function(e) {
    this.setData({
      isBranch: Boolean(this.data.model.nodes && this.data.model.nodes.length),
      open: !Boolean(this.data.model.selectshow == 1 && this.data.model.childshow != 0),
      checked: Boolean(this.data.model.checked)
    });
  },
})

tree.wxss頁面(稍作改變)

.treeClass
{
  line-height: 60rpx;
}

tree.json頁面(未做改動)

{
    "component": true,
    "usingComponents": {
      "mytree": "../tree/tree"
    }
}

Index.WXML頁面

<!--index.wxml-->
<view class="container">
    <mytree model='{{ treeData }}'  bind:clickNode='clickNode' id="myComponent"></mytree>
</view>
<view style="text-align:center">選中值爲{{objectId}}</view>

Index.json頁面

{
  "usingComponents": {
    "mytree": "../tree/tree"
  }
}

Index.js頁面

 

 

//index.js
//獲取應用實例
const app = getApp()
//treeList是原始數據,應該從接口中獲取的,在這裏就初始化好數據
var treeList = [ {
  CHILDSHOW: "0",
  CHOOSEWAY: "1",
  MATOBJID: "6",
  OBJINDEX: "1",
  OBJNAME: "默認情形",
  OBJPARENT: "0",
  SELECTSHOW: "1"
},  {
  CHILDSHOW: "0",
  CHOOSEWAY: "1",
  MATOBJID: "90",
  OBJINDEX: "3",
  OBJNAME: "測試對象",
  OBJPARENT: "0",
  SELECTSHOW: "1",
},  {
  CHILDSHOW: "0",
  CHOOSEWAY: "1",
  MATOBJID: "89",
  OBJINDEX: "2",
  OBJNAME: "測試節點",
  OBJPARENT: "1",
  SELECTSHOW: "0",
},  {
  CHILDSHOW: "0",
  CHOOSEWAY: "0",
  MATOBJID: "95",
  OBJINDEX: "8",
  OBJNAME: "子節點1.1",
  OBJPARENT: "2",
  SELECTSHOW: "1"
},  {
  CHILDSHOW: "1",
  CHOOSEWAY: "1",
  MATOBJID: "96",
  OBJINDEX: "9",
  OBJNAME: "子節點1.2",
  OBJPARENT: "2",
  SELECTSHOW: "1"
},  {
  CHILDSHOW: "1",
  CHOOSEWAY: "1",
  MATOBJID: "97",
  OBJINDEX: "10",
  OBJNAME: "子節點1.3",
  OBJPARENT: "2",
  SELECTSHOW: "1"
},  {
  CHILDSHOW: "0",
  CHOOSEWAY: "1",
  MATOBJID: "91",
  OBJINDEX: "4",
  OBJNAME: "測試節點2",
  OBJPARENT: "3",
  SELECTSHOW: "1"
},  {
  CHILDSHOW: "1",
  CHOOSEWAY: "1",
  MATOBJID: "92",
  OBJINDEX: "5",
  OBJNAME: "測試節點3",
  OBJPARENT: "3",
  SELECTSHOW: "1"
},  {
  CHILDSHOW: "1",
  CHOOSEWAY: "1",
  MATOBJID: "93",
  OBJINDEX: "6",
  OBJNAME: "子節點1",
  OBJPARENT: "4",
  SELECTSHOW: "1"
},  {
  CHILDSHOW: "1",
  CHOOSEWAY: "1",
  MATOBJID: "94",
  OBJINDEX: "7",
  OBJNAME: "子節點2",
  OBJPARENT: "4",
  SELECTSHOW: "1"
}]
//newTreeData用來存樹節點的數據,具體需要用到是否選中checked和是否展開open兩個字段
var newTreeData = [];
//初始化數據,刪除會影響初始化
//childshow子節點是否一直顯示,chooseway單選還是多選,selectshow子節點是否有選擇框
//下面的數據是初始數據,只用來對各個字段進行解釋
var treeData = {
    text: '不顯示的根節點', //顯示文字
    id: 1, //節點id
    parent: 0, //父節點的index
    childshow: 0, //子節點顯示方式 0是一直顯示,1是點擊父節點後子節點顯示出來
    chooseway: 0, //子節點的選擇方式,0是單選 1是多選
    index: 1, //父級和子級的關聯字段
    selectshow: 0, //是否顯示選擇框,0不顯示,1顯示
    parentchooseway: 0, //父級的子節點選擇方式,用來控制當前節點的展開方式
    parentnodes: '', //所有父節點集合,一直到第二級根節點,第一級根節點不需要,所以第二級的節點作爲根節點
    childnodes: '', //所有子節點集合
    siblingsnodes: '', //同級節點集合
    checked: false, //是否選中
    open: true, //子節點列表是否展開
    rootNode: 0, //根節點的index,指第二級根節點
    nodes: [{
      text: '根節點1',
      id: 2,
      parent: 1,
      childshow: 0,
      chooseway: 0,
      index: 2,
      selectshow: 0,
      parentchooseway: 0,
      parentnodes: '1',
      childnodes: '',
      siblingsnodes: '',
      checked: false,
      open: true,
      rootNode: 2
    }]
}
Page({
  data: {
    objectId: "", //獲取選中值
    treeData: treeData, //樹數據
  },
  onLoad: function() {
    //需要清空樹節點數據,不然會出錯
    newTreeData = [];
    treeData = {
      id: 0,
      childshow: 1,
      chooseway: 0,
      index: 0,
      selectshow: 0,
      checked: false,
      open: true,
      nodes: this.GetData(0, 0, treeList, "", 0, false, true, "", "", 0, "")
    };
    this.setData({
      treeData: treeData
    })
  },
  clickNode: function(e) {
    var treeData = {
      id: 0,
      childshow: 1,
      chooseway: 0,
      index: 0,
      selectshow: 0,
      checked: false,
      open: true,
      nodes: this.GetData(0, 0, treeList, e.detail.siblingsnodes, e.detail.itemid, e.detail.checked, e.detail.open, e.detail.parentnodes, e.detail.childnodes, e.detail.rootNode, e.detail.type)
    };
    var checkedObjID = this.getCheckedObject();
    this.setData({
      isShowObject: true,
      treeData: treeData,
      objectId: checkedObjID
    })
    this.selectComponent('#myComponent').reInit();
  },
  //獲取被選中的情形ID集合
  getCheckedObject() {
    var str = "";
    for (var i in newTreeData) {
      //當被選中且有選擇框時
      if (newTreeData[i].checked && newTreeData[i].selectshow == 1) {
        str += str == "" ? newTreeData[i].id : "," + newTreeData[i].id
      }
    }
    return str;
  },
  //根據菜單主鍵id獲取下級菜單        
  //id:菜單主鍵id        
  //arry:菜單數組信息        
  GetParentArry(id, arry) {
    var newArry = new Array();
    for (var i in arry) {
      if (arry[i].OBJPARENT == id) newArry.push(arry[i]);
    }
    return newArry;
  },
  //獲取父級字符串
  GetParentStr(id, str, arry) {
    for (var i in arry) {
      if (arry[i].OBJINDEX == id && arry[i].OBJPARENT != 0) {
        var objparent = arry[i].OBJPARENT;
        str += str == "" ? arry[i].OBJPARENT : "," + arry[i].OBJPARENT
        str = this.GetParentStr(objparent, str, arry);
        break;
      }
    }
    return str;
  },
  //獲取第二級根節點ID
  GetRootNode(id, arry) {
    var str = "";
    for (var i in arry) {
      if (arry[i].OBJINDEX == id) {
        if (arry[i].OBJPARENT == 0) {
          str = arry[i].OBJINDEX
        } else {
          str = this.GetRootNode(arry[i].OBJPARENT, arry);
        }
        break;
      }
    }
    return str;
  },
  //獲取子級字符串
  //arr是需要查找子級的參數集合
  //str是子級字符串
  //tempstr是存放臨時字符串的,用來判斷每個參數是否有子級
  GetChildStr(arr, str, tempstr, arry) {
    for (var j in arr) {
      tempstr = ""; //每個參數進行判斷子級時把該值設爲空
      for (var i in arry) {
        if (arry[i].OBJPARENT == arr[j]) {
          str += str == "" ? arry[i].OBJINDEX : "," + arry[i].OBJINDEX;
          tempstr += tempstr == "" ? arry[i].OBJINDEX : "," + arry[i].OBJINDEX;
        }
      }
      if (tempstr != "") {
        str = this.GetChildStr(tempstr.split(','), str, "", arry);
      }
    }
    return str;
  },
  //id:index 
  //arry:節點數組
  //parentchooseway 父節點的子節點顯示方式
  //siblings 被選中節點的同級元素index集合
  //curid 被選中節點的id
  //curchecked 當前節點應該要顯示的是否選中狀態
  //curopen 當前節點應該要顯示的子節點是否展開狀態
  //parentnodes 當前節點的父級元素index集合,先查它的父級,再查父級的父級,直到根節點。這些父級組成的字符串
  //childnodes 當前節點的所有子級元素index集合
  //rootNode 當前節點的根節點的index,實際上是第二級根節點
  //type 選中節點的選擇框類型
  GetData(id, parentchooseway, arry, siblings, curid, curchecked, curopen, parentnodes, childnodes, rootNode, type) {
    var nodeList = [];
    var childArry = this.GetParentArry(id, arry);
    if (childArry.length > 0) {
      let siblingsNodes = "";
      //獲取此父級下的所有節點
      for (var i in childArry) {
        siblingsNodes += siblingsNodes == "" ? childArry[i].OBJINDEX : "," + childArry[i].OBJINDEX;
      }
      //循環所有子節點
      for (var i in childArry) {
        //當前節點的根節點
        var currootNode = this.GetRootNode(childArry[i].OBJINDEX, arry);
        var childList = [];
        //遞歸查找子節點集合
        childList = this.GetData(childArry[i].OBJINDEX, childArry[i].CHOOSEWAY, arry, siblings, curid, curchecked, curopen, parentnodes, childnodes, rootNode, type);
        var tempStr = "";
        //獲取同一級別節點,處於同一個父級下
        if (siblingsNodes != "") {
          tempStr = ("," + siblingsNodes + ",").replace("," + childArry[i].OBJINDEX + ",", ",");
          if (tempStr != "") {
            //去掉首尾逗號
            tempStr = tempStr.replace(/^,+/, "").replace(/,+$/, "")
          }
        }
        let objindex = childArry[i].OBJINDEX;
        let parentstr = this.GetParentStr(objindex, "", arry);
        let childstr = this.GetChildStr([objindex], "", "", arry);
        let tempNode = {};
        //用來獲取這個數據原先的數據
        if (newTreeData.length == arry.length) {
          for (var k in newTreeData) {
            if (newTreeData[k].index == childArry[i].OBJINDEX) {
              tempNode = newTreeData[k];
            }
          }
        }
        //如果該節點不是選中節點的父節點,或者原先無樹數據集合,或者當前點擊後是選中,這些情況下需要走多個判斷來確定樹節點的選中及展開情況
        //正常情況下newTreeData和arry的長度是一致的,如果不一致,是因爲初次加載樹時newTreeData爲空
        if (("," + parentnodes + ",").indexOf("," + childArry[i].OBJINDEX + ",") == -1 || newTreeData.length < arry.length || curchecked == true) {
          let check = false;
          //如果這個是選中的節點就用返回回來的值
          if (curid == childArry[i].MATOBJID) {
            check = curchecked
          } else if (("," + parentnodes + ",").indexOf("," + childArry[i].OBJINDEX + ",") > -1 && curchecked == true) {
            //如果該節點是選中節點的父級,且當前節點是選中,那麼父級也都是選中
            check = true;
          } else if (("," + childnodes + ",").indexOf("," + childArry[i].OBJINDEX + ",") > -1 && curchecked == false) {
            //如果該節點是選中節點的子級,且當前節點是未選中,那麼子級都是不選中
            check = false;
          } else if ((type == "checkbox" || (type == "radio" && ("," + siblings + ",").indexOf("," + childArry[i].OBJINDEX + ",") == -1)) && currootNode == rootNode) //tempNode.selectshow == 1 && tempNode.parentchooseway == 1
          {
            //如果勾選的是多選框,並且處於同一個根節點下就還是用原先的選中狀態
            //如果勾選的是單選框,且不處於同級,並且處於同一個根節點下就還是用原先的選中狀態
            check = tempNode.checked;
          }
          let isopen = true;
          //如果有選擇框,並且子節點不是一直顯示,再加上未選中那麼不展開,當check爲false時才進方法
          if (childArry[i].SELECTSHOW == 1 && childArry[i].CHILDSHOW != 0 && !check) {
            isopen = false;
          }
          if (curid == childArry[i].MATOBJID && childArry[i].SELECTSHOW == 1 && childArry[i].CHILDSHOW != 0) {
            //如果當前節點是選中的節點,並且子節點的顯示方式是點擊顯示(1),那麼值取傳過來的值
            isopen = curopen
          }
          //nodeList存節點的所有數據且和子節點有層級關係
          nodeList.push({
            text: childArry[i].OBJNAME,
            id: childArry[i].MATOBJID,
            parent: childArry[i].OBJPARENT,
            childshow: childArry[i].CHILDSHOW,
            chooseway: childArry[i].CHOOSEWAY,
            index: childArry[i].OBJINDEX,
            selectshow: childArry[i].SELECTSHOW,
            parentchooseway: parentchooseway,
            parentnodes: parentstr,
            childnodes: childstr,
            siblingsnodes: tempStr,
            checked: check,
            open: isopen,
            rootNode: currootNode,
            nodes: childList
          });
          //如果是初次加載的話就把樹節點的一些基本信息存儲在newTreeData中
          //如果不是初次加載的話就把樹節點的信息修改下就行,一般只需要修改是否展開和是否選中兩個字段
          if (newTreeData.length < arry.length) {
            newTreeData.push({
              text: childArry[i].OBJNAME,
              id: childArry[i].MATOBJID,
              parent: childArry[i].OBJPARENT,
              childshow: childArry[i].CHILDSHOW,
              chooseway: childArry[i].CHOOSEWAY,
              index: childArry[i].OBJINDEX,
              selectshow: childArry[i].SELECTSHOW,
              parentchooseway: parentchooseway,
              checked: check,
              open: isopen,
              rootNode: currootNode
            })
          } else {
            for (var num in newTreeData) {
              if (newTreeData[num].index == childArry[i].OBJINDEX) {
                newTreeData[num].checked = check;
                newTreeData[num].open = isopen;
                break;
              }
            }
          }
        } else {
          //這種是上面三種情況都不是的時候,這時候這個節點就用它原本的數據就行,不需要改變
          if (tempNode.index == childArry[i].OBJINDEX) {
            nodeList.push({
              text: tempNode.text,
              id: tempNode.id,
              parent: tempNode.parent,
              childshow: tempNode.childshow,
              chooseway: tempNode.chooseway,
              index: tempNode.index,
              selectshow: tempNode.selectshow,
              parentchooseway: tempNode.parentchooseway,
              parentnodes: parentstr,
              childnodes: childstr,
              siblingsnodes: tempStr,
              checked: tempNode.checked,
              open: tempNode.open,
              nodes: childList,
              rootNode: tempNode.rootNode
            });
          }
        }
      }
    } else {
      nodeList = [];
    }
    return nodeList;
  },
})

 Index.wxss無內容

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章