1. 程式人生 > 其它 >微信小程式元件Components——父向子傳遞和子向父傳遞資料的過程

微信小程式元件Components——父向子傳遞和子向父傳遞資料的過程

前言:元件是微信小程式在開發過程中一個非常重要的知識,可以化簡我們的程式碼複用及編寫,但是元件也是相對來說比較難以理解的一個概念,用法也比較糾結,本篇博文將具體介紹元件的基本使用方法

一、簡單瞭解
元件的建立其實和頁面很像,其實就是把多個標籤通過一定的邏輯整合到了一起形成元件
在這裡插入圖片描述
這是元件的所需檔案,可以看出和頁面很像,當然也有些不同
比如在json配置檔案中多了 “component”: true的內容

{
  "component": true,
  "usingComponents": {}
}

在js檔案中多了properties和method屬性等

properties: {
    tabs:{
      type:Array,
      value:[]
    }
  },
  methods: {
  
  }

在使用外掛的是時候,父級頁面需要進行宣告,在json配置頁面中如何設定

{
  "usingComponents": {
  //相對路徑應用元件
    "Tabs":"../../components/Tabs/Tabs"
  },
  "navigationBarTitleText": "梨花燒"
}

二、元件的使用
例如,想做一個標籤頁面

在這裡插入圖片描述
子元件wxml頁面

<view calss="tab"> 
  <view class="tabs_title">
    <view class="title_item {{item.isActive?'active':''}}" 
    wx:for="{{tabs}}" 
    wx:key="id" 
    bindtap="handleItemTap" 
    data-index="{{index}}"
>{{item.name}}</view> </view> <view class="tabs_content"> <slot></slot> </view> </view>

子元件js頁面如下

// components/Tabs/Tabs.js
Component({
  /**
   * 元件的屬性列表
   */
  properties: {
    tabs:{
      type:Array,
      value:[]
    }
  },

  /**
   * 元件的初始資料
   */
  data: {
  },

  /**
   * 元件的方法列表
   */
  methods: {
    handleItemTap(e){
      const {index} = e.currentTarget.dataset;
      this.triggerEvent("itemChange",{index});
    }
  }
})

父頁面wxml

<Tabs tabs="{{tabs}}" binditemChange="handleItemChange">
  <block wx:if="{{tabs[0].isActive}}">0</block>
  <block wx:elif="{{tabs[1].isActive}}">1</block>
  <block wx:elif="{{tabs[2].isActive}}">2</block>
  <block wx:else>3</block>
</Tabs>

父頁面js

Page({

  /**
   * 頁面的初始資料
   */
  data: {
    tabs:[
      {
        id:0,
        name:"首頁",
        isActive:true
      },
      {
        id:1,
        name:"原創",
        isActive:false
      },
      {
        id:2,
        name:"分類",
        isActive:false
      },
      {
        id:3,
        name:"關於",
        isActive:false
      }
    ]
  },
  handleItemChange(e){
    console.log(e);
    const {index} = e.detail;
    let {tabs} = this.data;
      tabs.forEach(function(v,i){
        if(i===index){
          v.isActive=true;
        }else{
          v.isActive=false;
        }
      });
      let num=2;
      this.setData({
        tabs,
        num
      });
  }
})

需要注意下子元件js中properties屬性就是父向子傳遞資料的入口,(注:在子元件中使用let {tabs} = this.data;仍然可以獲得tabs,雖然data中沒有tabs資料,但是可以在properties中獲取,但是如果再將資料進行setData操作的話,就會儲存再data中,而不是properties),需要設定type型別和value初始值,父頁面可以採用下面的方式設定

<Tabs tabs="{{tabs}}">

這樣的話,就可以將父頁面的資料傳送到子元件中了。

但是子元件中有時候會有一些操作又需要將資料反饋到父頁面中,比如需要向第幾個頁面的資訊通知給父頁面,可以子元件wxml中加入單擊事件,然後通過this.triggerEvent(“itemChange”,{index});繫結並呼叫父頁面繫結事件binditemChange,使用如下程式碼實現

    handleItemTap(e){
      const {index} = e.currentTarget.dataset;
      this.triggerEvent("itemChange",{index});
    }

然後在父頁面中來設定觸發方法

<Tabs binditemChange="handelItemChange">

這樣就可以如法父頁面js中的handelItemChange方法了,

handelItemChange(e){
    console.log(e);
}

通過列印e得到如下資料,可以從e.detail.index中獲取子元件傳回的資料了

{type: "itemChange", timeStamp: 955073, target: {}, currentTarget: {}, detail: {},}
changedTouches: undefined
currentTarget: {id: "", dataset: {}}
detail: {index: 2}
target: {id: "", dataset: {}}
timeStamp: 955073
touches: undefined
type: "itemChange"
_requireActive: undefined
__proto__: Object

簡單回顧以下這個的流程:
1.父頁面呼叫子元件,單擊等事件操作的響應其實在子元件的;
2.子頁面呼叫單擊事件相應,並繫結父頁面的ItemChange方法;
3.父頁面通過bindItemChange屬性來繫結handleItemChange(e)方法,通過e引數將子資料返回給父頁面
所以實際上父頁面的bindItemChange屬性並不是父頁面直接單擊生效的,我想button按鈕的bindtop單擊出發事件也是通過類似的繫結

可能有人會問這樣傳來傳去的意義是什麼呢,因為元件建立後,可能被多個頁面多次呼叫,所以很多程式碼都是動態設定的,不能直接寫死,很多元件的資料需要父頁面的資料來決定,而且元件的資料如果發生變動的話,不能再子元件中更新資料,這樣的資料會儲存子元件的data中,父頁面的資料無法更新,所以一般再元件中不進行復雜的邏輯操作,直接將簡單的資料資訊傳送給父頁面,讓父頁面處理資料,保證父頁面資料的實時更新。


最後在說一下插槽標籤的作用

可以將<Tabs>內容</Tabs>中的“內容”替換到掉<slot></slot>