微信小程序component父子組件傳值

在某些場景,用到組件還是比較多的。例如,在頁面的底部有一個懸浮,懸浮分兩種,每種裏邊有四個按鈕,每個按鈕分爲登錄和沒登錄兩個狀態,點擊每個按鈕繪根據後臺傳的值的狀態不同分別請求不同的接口(當然了,有些處理完頁面也可能是跳轉,或者跳轉webview,或者reLaunch某個頁面......)。總之一句話,這個底部懸浮比較麻煩,考慮的場景比較多,然後呢,好多頁面都會用到,不用寫那麼多的重複代碼,寫好一個組件,大家都來調用,用的簡單,維護也簡單。

下邊我用一個簡單的場景來舉例,複雜場景原理相同,只不過是根據業務場景再做處理即可。

我的場景:頁面中的按鈕存在登錄和未登錄兩個狀態,組件中的按鈕也存在這兩個狀態,任何一處授權登錄過了,整個小程序的登錄狀態都會改變。此時若把父組件的登錄狀態改變,就要傳給子組件;子組件的登錄狀態改變,父組件也跟着變。但父子組件又相互獨立,此時就要通過某種方式來相互傳值。

1.組件('component/btn/btn’)

1.1.wxml

<view wx:if="{{isLogin}}" class='btn' catchtap='clickme'>子  組件的view</view>

<button wx:if="{{!isLogin}}" class='btn' open-type="getPhoneNumber" lang="zh_CN" bindgetphonenumber="getPhoneNumber">子 組件的button</button>

1.2.wxss

.btn{
  width: 250rpx;
  height: 50rpx;
  line-height: 50rpx;
  text-align: center;
  background-color: orange;
  font-size: 20rpx;
  color: #fff;
  margin-left: 0;
  border-radius: 10rpx;
  padding: 0 20rpx;
  box-sizing: border-box;
  margin: 20rpx 20rpx;
}

.btn::after{
  border: 0;
}

1.3js

const app = getApp();
Component({
  behaviors: [],
  // 屬性定義(詳情參見下文)
  properties: {
    isLogin: {
      type: Number,
      value: 0,
    }
  },
  data: {

  }, // 私有數據,可用於模板渲染

  lifetimes: {
    // 生命週期函數,可以爲函數,或一個在methods段中定義的方法名
    attached: function () {
      // console.log(111111111111)
      var that = this;
    },
    moved: function () {
      // console.log(2222222222222)
    },
    detached: function () {
      // console.log(3333333333333)
    },
  },

  // 生命週期函數,可以爲函數,或一個在methods段中定義的方法名
  attached: function () {
    // console.log(4444444444444)
  }, 
  ready: function () {
    // console.log(5555555555555555)

  },

  pageLifetimes: {
    // 組件所在頁面的生命週期函數
    show: function () {
      // console.log(666666666666666666)
      var that = this;
    },
    hide: function () {
      // console.log(777777777)
    },
    resize: function () {
      // console.log(88888888888888)
    },
  },

  methods: {
    clickme(e,aa='子請求接口'){
      console.log(aa)
    },
    getPhoneNumber: function (e) {
      var that = this;
      if (e.detail.errMsg == "getPhoneNumber:ok") {
        var param = {
          iv: e.detail.iv,
          encryptedData: e.detail.encryptedData,
          logintype: 2
        }

        /**logintype:2時授權登錄**/
        that.setData({
          isLogin: true,
        });

        that.clickme(e,'子授權後請求接口')

        var loginState = {
          isLogin: 1
        };
        that.triggerEvent("triggerBottom", loginState);
      } else {
        wx.showToast({
          title: '子授權失敗',
          icon: 'none',
          duration: 3000
        });
      }

    },
  },
});

1.4json

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

2.調用組件的文件

2.1wxml

<view wx:if="{{isLogin}}" class='btn'>父  組件的view</view>

<button wx:if="{{!isLogin}}" class='btn' open-type="getPhoneNumber" lang="zh_CN" bindgetphonenumber="getPhoneNumber">父  組件的button</button>

<fixbottom isLogin="{{isLogin}}" bind:triggerBottom="triggerBottom"></fixbottom>

2.2wxss

.btn{
  width: 250rpx;
  height: 50rpx;
  line-height: 50rpx;
  text-align: center;
  background-color: orange;
  font-size: 20rpx;
  color: #fff;
  margin-left: 0;
  border-radius: 10rpx;
  padding: 0 20rpx;
  box-sizing: border-box;
  margin: 20rpx 20rpx;
}

.btn::after{
  border: 0;
}

2.3js

var that;
Page({

  /**
   * 頁面的初始數據
   */
  data: {
    isLogin: 0
  },
  /**
   * 生命週期函數--監聽頁面加載
   */
  onLoad: function(options) {
    that = this;
  },

  triggerBottom(e) {
    var isLogin = e.detail.isLogin == 1 ? e.detail.isLogin : 0;
    that.setData({
      isLogin: isLogin
    });
  },
  clickme(e, aa = '父請求接口') {
    console.log(aa)
  },
  getPhoneNumber: function(e) {
    var that = this;
    if (e.detail.errMsg == "getPhoneNumber:ok") {
      var param = {
        iv: e.detail.iv,
        encryptedData: e.detail.encryptedData,
        logintype: 2
      }

      /**logintype:2時授權登錄**/
      that.setData({
        isLogin: true,
      });

      that.clickme(e, '父授權後請求接口')

    } else {
      wx.showToast({
        title: '父授權失敗',
        icon: 'none',
        duration: 3000
      });
    }

  },
})

2.4json

{
  "usingComponents": {
    "fixbottom": "/component/btn/btn"
  }
}

3.說明

3.1小程序和vue類似,雙向數據綁定,組件其實就是一個標籤,在這個標籤上可以綁定一個數據,可以綁定一個事件,當然了,這個綁定的數據(或者事件)都須要遵從組件的規則。

3.2 父集向子集傳值,直接傳就好了,父集變子集跟着變。子集的值變,要想派發給父集,必須通過‘triggerEvent’來實現,派發出去。

3.3 現在的組件生命週期好像存在一些問題,第一次進入只執行了lifetimes裏的attached和ready兩個,pageLifetimes裏的show沒執行,看文檔的意思pageLifetimes應該是和頁面的聲明週期同步,但沒有(可能是個bug吧,嘻嘻)。但當頁面被back時會執行show生命週期(感覺還是有點不靠譜)。

3.4對於一進頁面和back回來都需要檢測登狀態(或者其他的狀態值的)建議在attached中執行一次接口請求,然後再show中也執行一次(如果這個值在緩存中,可以做一個判斷,如果爲真就不再請求,否則會請求),不然就會不靠譜,哈哈。

3.5在寫回調方法時,注意一下寫法,否則會出現意想不到的驚喜哦

  dayin(aa='默認參數'){
    console.log(aa)
  },
  dioyong(cb) {
    typeof cb == "function" && cb();
  },

  right(cb) {
    var that = this;
    this.dioyong(function(){
      that.dayin('this is right')
    });
  },
  wrong() {
    var that = this;
    this.dioyong(that.dayin('this is wrong'))
  }

例如上邊的right方法和wrong方法,看着好像都對,你自己在本地調用運行一下。

直接寫結論了,right方法確確實實是當回調函數來執行的,wrong方法並不是,尤其是在接口調用,涉及接口調用順序的情況就會出錯。wrong裏的調用,加了括號,相當於函數調用語句直接執行了,就沒走  typeof cb == "function" && cb() 。而right確實是一個function(哈哈,應該是這個原因吧)。

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