1. 程式人生 > 其它 >小程式triggerevent 傳參_微信小程式——無限遞迴的層次列表

小程式triggerevent 傳參_微信小程式——無限遞迴的層次列表

技術標籤:小程式triggerevent 傳參

——上禮拜踩的坑

1、關於為什麼不直接操作DOM物件?

因為微信小程式裡沒有document物件。

2、為什麼坑了這多時間?

因為之前看了個過期的帖子,完美避開了解決方案。

下面進入正文,需求是在微信小程式裡構造一棵檔案樹。

3、解決思路

定義一個自定義元件,並在這個元件裡遞迴自己。

4、自定義元件.json檔案

{
  "component": true,
  "usingComponents": {
    "alexTree":"path/to/component"
  }
}

由於元件要引用自己,所以這裡定義了元件自己。

“alexTree”是元件裡引用自己時用的標籤名,理論上是可以自定義的,只要在wxml檔案j裡對應起來就好。

5、元件的property定義

  properties: {
    treeBody:{
      type: Array,
      value:[],
      observer: function (newVal, oldVal, changedPath) {

      }
    },
    treeConfig:{
      type:Object,
      value:{
        haveOpGroup:false,
        haveIconGroup:false,
        opGroup:{
          label:"",
          icon:"",
          onTap:function(node){
            console.log("opGroup tapped.");
          }
        },
        tapOnNode:function(node){
          console.log("tapOnNode");
        }
      },
      observer: function(newVal, oldVal, changedPath) {
      }
    },
  },

主要定義了兩個屬性,一個是資料tree-body,一個是配置tree-config。

資料結構本身當然也是遞迴的。tree-body是一個數組(根目錄),其中的元素作為檔案,一個檔案可以是一個普通檔案,也可以是一個目錄檔案,用元素的isDir屬性來區分,如下:

{
   filename:<String>
   isDir:<Boolean>
   data:<Array>/<Object>
}

filename是檔名,當isDir為true時,data為子檔案陣列,當isDir為false時,data為與檔案相關的自定義資料,例如檔案在伺服器的url等。

6、 wxml大致結構。

<view wx:for="{{treeBody}}">
  <!-- 這裡為當前節點的構造邏輯 -->
  <view class='treeNode' catchtap="tapOnNode" data-node='{{item}}'> <<<<<<vviieew>>>>>>>>>
  <!-- balabala -->
  <!-- balabala -->
  <!-- balabala -->
  <!-- 然後判斷此節點是否展開,下面的邏輯裡,如果這個節點為展開狀態的目錄,就遞迴此元件 -->
  <!-- 注意alexTree為上面json檔案裡定義的 -->
  <view class='childNodes'>
    <alexTree wx:if="{{item.isDir && item.expand}}" tree-body="{{item.data}}" tree-config="{{treeConfig}}" data-filename="{{item.filename}}" bindnodechanged="_handleChildNodeChanged"/>
  </view>
</view>

7、點選節點更改目錄展開狀態

   tapOnNode:function(e){
      // 點選節點時,摺疊或展開結點(目錄)
      var tmpNode = e.currentTarget.dataset.node;
      var filename = tmpNode.filename;
      var nodes = this.data.treeBody;
      var node = this._findNodeByName(nodes,filename);
      if(!node){
        return;
      }
      if(node.isDir){
        if(node.expand){
          delete node.expand;
        }else{
          node["expand"] = 1;
        }
      }
      this._refreshTree(nodes);
      // 呼叫treeConfig.tapOnNode
      if(this.data.treeConfig.tapOnNode){
        this.data.treeConfig.tapOnNode();
      }
    },

8、另一個問題

傳遞給子節點的資料為深複製之後的陣列,所以改變子節點的資料,不會影響到父節點的資料。當父節點目錄摺疊時,重新展開後,子節點的狀態無法儲存。

解決方案:當子節點資料改變時,丟擲一個自定義事件,父節點捕捉這個事件,同時更改自己的資料。

    // 重新整理樹
    _refreshTree:function(nodes){
      this.setData({
        treeBody : nodes,
      });
      // 然後向父結點丟擲一個nodeChanged事件
      var filename = this.dataset.filename;
      var myEventDetail = { 
        filename: filename,
        nodes: nodes,
        } // detail物件,提供給事件監聽函式
      var myEventOption = {} // 觸發事件的選項
      this.triggerEvent('nodechanged', myEventDetail, myEventOption)
    },
    _handleChildNodeChanged:function(e){
      // 處理子結點丟擲的nodeChanged事件
      var filename = e.detail.filename;
      var nodes = this.data.treeBody;
      for (var i = 0; i < nodes.length; i++) {
        if (nodes[i].filename == filename) {
          nodes[i].data = e.detail.nodes;
        }
      }
      this.setData({
        treeBody: nodes,
      });
    },