跟我學(xué)微信小程序之三(數(shù)據(jù)共享篇)

告別比較晦氣的2020,迎來嶄新的2021年,希望一切都順利,特別是家人,朋友都能身體健康,健康比一切都重要,沒有健康一切都是浮云。2021年,除了好好工作外,我給自己立個(gè)小目標(biāo),爭取每周一篇原創(chuàng)文章,雖然不能像那些大V一樣把它當(dāng)成一份自由職業(yè),但也要向夢想出發(fā),萬一夢想哪天實(shí)現(xiàn)了呢?
上篇文章介紹了小程序中的自定義組件相關(guān)的內(nèi)容,包括如何定義組件,組件和頁面如何相關(guān)通訊。這篇文章將寫點(diǎn)關(guān)于數(shù)據(jù)共享的一些相關(guān)內(nèi)容。包括全局?jǐn)?shù)據(jù)共享,behaviors和mobix技術(shù)在小程序中的應(yīng)用。

一個(gè)實(shí)例

從一個(gè)實(shí)際例子開始,在下面的一個(gè)小程序中,點(diǎn)擊俱樂部介紹將進(jìn)入俱樂部詳細(xì)介紹頁面,下面是當(dāng)前俱樂部近期活動(dòng)列表。因此有兩個(gè)頁面,他們之間需要共享數(shù)據(jù),第一個(gè)頁面里將獲取到俱樂部的信息,包括俱樂部介紹的內(nèi)容,這個(gè)內(nèi)容將傳遞到第二個(gè)頁面,俱樂部詳細(xì)頁面。


Screen Shot 2021-01-02 at 12.32.49 PM.png
問題一:組件間數(shù)據(jù)共享

這是一個(gè)典型的頁面導(dǎo)航例子,可以有以下方案:
方式一,第一個(gè)頁面中獲取數(shù)據(jù),然后通過在navigator的url中傳遞數(shù)據(jù)到第二個(gè)頁面,這種方式有兩個(gè)問題,第一是url有長度限制,對于數(shù)據(jù)量小的方式可行,但是對于大數(shù)據(jù),會(huì)超過url的長度限制。其二是只能傳遞字符串內(nèi)容,對于對象的傳遞,需要序列化轉(zhuǎn)成json字符串,然后反序列化為對象。因此,這種方式對于我們的場景不太合適。
方式二,使用全局函數(shù)和全局?jǐn)?shù)據(jù),這是小程序提供的跨組件數(shù)據(jù)交互的一個(gè)方式,使用方式也比較簡單,就是在app.js里定義全局函數(shù)和全局變量,在需要的頁面里使用getApp來獲取全局對象。這種方式個(gè)人覺得比較適合于存儲(chǔ)一些與業(yè)務(wù)無關(guān)的對象,而且每個(gè)頁面都需要的全局對象,比如用戶身份信息,系統(tǒng)初始數(shù)據(jù)等對象,而不應(yīng)該把與業(yè)務(wù)相關(guān)的而且是只針對個(gè)別頁面相關(guān)的信息存儲(chǔ)到全局變量中。
方式三,使用behaviors,behaviors 是用于組件間代碼共享的特性。但它不適用于組件間數(shù)據(jù)共享,一個(gè)頁面中對數(shù)據(jù)的更新不會(huì)影響到另一個(gè)頁面中的數(shù)據(jù)狀態(tài)。因此,也不適用于此場景。
方式四,使用緩存方式,這種方式可以實(shí)現(xiàn)對數(shù)據(jù)的共享,第一個(gè)頁面獲取到數(shù)據(jù)后使用wx.setStorageSync來存儲(chǔ)信息,在其他頁面中使用wx.getStorageSync來從緩存中同步讀取信息。

問題二,組件間代碼共享

另一個(gè)問題是下方的下拉列表,這個(gè)是一個(gè)列表組件,每個(gè)列表組件都有一些公共的方法,比如分頁信息,下拉刷新,觸底加載等,這些是每個(gè)列表組件都需要的,因此,可以使用組件間代碼共享behaviors來實(shí)現(xiàn)。

全局?jǐn)?shù)據(jù)共享

全局?jǐn)?shù)據(jù)共享是簡單的數(shù)據(jù)共享方式,它是小程序框架提供的一種全局?jǐn)?shù)據(jù)共享的方式,如果熟悉javascript的同學(xué)應(yīng)該很容易理解,在網(wǎng)頁開發(fā)中,經(jīng)常會(huì)定義一個(gè)全局類來存儲(chǔ)一些app中的公共信息,在其他頁面中import此全局實(shí)例,然后對此全局實(shí)例進(jìn)行g(shù)et或set。小程序框架也類似,只是它規(guī)定了此文件的位置,以及全局變量放置的位置。
全局變量在app.js中定義。比如,我們定義一個(gè)global_UserInfo對象

App({
  onLaunch: function () {

  },
  globalData: {
    g_userInfo: {}
  }
})

在需要獲取該變量的頁面.js文件中按照如下代碼即可獲取。

var app = getApp();
Page({
  data: {
    userInfo: app.globalData.g_userInfo
  }
})

獲取之后進(jìn)行修改也很簡單,只需直接賦值即可。

app.globalData.g_userInfo = {
  "name":"David",
  “role":"admin"
};

使用是不是很簡單,但是建議不能把globalData當(dāng)成一個(gè)大垃圾桶,什么東西都往里面裝,雖然使用最簡單,但業(yè)務(wù)相關(guān)的東西,盡量不要放在全局變量中,避免污染。

Behaviors

behaviors 是用于組件間代碼共享的特性,類似于一些編程語言中的 “mixins” 或 “traits”。作用有點(diǎn)類似于面向?qū)ο缶幊汤锏念惱^承,抽象出一些類的屬性和方法放在父類中,派生類可以繼承父類的方法,同時(shí)可以重載父類的方法。在小程序中,behavior中定義一些公共的屬性,數(shù)據(jù)和方法,組件導(dǎo)入這些behavior,進(jìn)而就有了behavior的屬性,數(shù)據(jù)和方法,同時(shí),組件還可以覆蓋behavior里的屬性和方法。同樣一個(gè)子類實(shí)例對父類的數(shù)據(jù)修改也不會(huì)影響到其他子類實(shí)例。
小程序官網(wǎng)

https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/behaviors.html

詳細(xì)介紹了behaviors的概念以及使用?;旧暇W(wǎng)上搜索到的例子也都是來自官網(wǎng)的這個(gè)例子,我就不再抄一遍了。關(guān)鍵注意以下幾點(diǎn):

  • 每個(gè)behavior包含一組屬性,數(shù)據(jù),方法和聲明周期函數(shù)。
  • 每個(gè)組件可以引用多個(gè)behavior,behavior可以引用其他的behavior
  • 當(dāng)組件引用behavior時(shí),behavior的屬性、數(shù)據(jù)和方法會(huì)被合并到組件中,生命周期函數(shù)也會(huì)在對應(yīng)時(shí)機(jī)被調(diào)用。 如下是引入behavior后,組件的屬性,數(shù)據(jù),方法和生命周期。
    1)屬性:behavior的屬性、組件自身的屬性
    2)數(shù)據(jù)字段:behavior的data、組件自身的data
    3)方法:behavior的方法、組件自身的方法
    4)生命周期函數(shù):attached、created、ready
    behavior created方法-->組件的created方法-->behavior的attach方法-->組件的created方法-->behavior的ready方法-->組件的ready方法
  • behavior不能實(shí)現(xiàn)組件間數(shù)據(jù)共享,一個(gè)組件改變behavior的data,不會(huì)影響到另一個(gè)引用此behavior的組件。這個(gè)很重要,behavior只是代碼的共享,它不能實(shí)現(xiàn)組件的數(shù)據(jù)共享。
    在上面的實(shí)例中,我把導(dǎo)航列表相關(guān)的一些屬性,數(shù)據(jù)和方法提煉出來放在一個(gè)navigatorListBehavior中,在我的組件中引入了此behavior,然后就可以共享這些代碼,不需要在每個(gè)導(dǎo)航列表組件中都重復(fù)定義這些數(shù)據(jù),屬性和方法。代碼如下:
let navigatorListBehavior = Behavior({
  behaviors: [],
  properties: {
    title: {
      type: String
    }
  },
  data: {
    pageNumber: 0,
    pageSize: 10,
    isDisableLoading: false,
    isLoading: false
  },
  attached: function () {},
  methods: {
    scrollBottom: function (e) {
      if (this.data.isLoading) {
        console.log("waiting...")
        return;
      }
      this.setData({
        isLoading: true
      });
      this.showData();
    },
    calculateSwiperHeight: function () {
      var that = this
      wx.getSystemInfo({
        success: function (res) {
          that.setData({
            clientHeight: res.windowHeight
          });
        }
      })
    },
    listLoadSucceed(){
      wx.hideLoading();
      wx.stopPullDownRefresh();
      this.setData({
        pageNumber: this.data.pageNumber + 1,
        isLoading:false
      });
    },
    isDisableLoading(response){
      if(response.length == 0){
        this.setData({
          isDisableLoading:true
        })
        return true;
      }
      return false;
    },
    listLoadFailed(prompt, reason){
      wx.hideLoading();
      wx.showToast({
        title: prompt + '加載失敗,原因' + res,
        duration: 5000
      });
      this.setData({
        isLoading: false
      });
    },
    canLoad(){
      return !this.data.isDisableLoading;
    },
    startLoading(){
      wx.showLoading({
        title: '努力加載中...',
      });
    },
    reset(){
      this.setData({
        pageNumber:0,
        isLoading:false,
        isDisableLoading:false
      })
    
    }
  }
})
export {
  navigatorListBehavior
}

定義完behavior后,我們可以在組件或者頁面里引用此behavior,這樣組件或者頁面就有了behavior的屬性,方法和數(shù)據(jù)。比如下面的代碼片段,就可以直接使用方法,比如canLoad, listLoadSucceed, listLoadFailed,數(shù)據(jù)pageNumber,pageSize等。

import {
  navigatorListBehavior
} from '../navigatorListBehavior.js'
Page({
  behaviors: [navigatorListBehavior],
  showData: function () {
    if (!this.canLoad()) {
      return;
    }
    this.startLoading();
    this.getData(res => {
      console.log(res);
      this.listLoadSucceed();
      if (this.isDisableLoading(res)) {
        return;
      }
      this.currentActivityList.loadData(res);

    }, res => {
      console.log(res);
      this.listLoadFailed('活動(dòng)列表', res);
    })
  },
  getData: function (successCallback, failedCallback) {
    wx.cloud.callFunction({
      name: 'club',
      data: {
        action: "requestMyActivitiesByStatus",
        status: status,
        pageNumber: this.data.pageNumber,
        pageSize: this.data.pageSize
      }
    }).then(res => {
      successCallback(res.result);
    }).catch(res => failedCallback(res));
  },
})

Mobx數(shù)據(jù)共享

還是回到之前的實(shí)例,俱樂部介紹頁面需要用到俱樂部頁面的數(shù)據(jù),這時(shí)候使用behavior是不能實(shí)現(xiàn)的,因?yàn)槭莾蓚€(gè)組件或頁面之間需要共享數(shù)據(jù),而不是代碼級別的共享。全局?jǐn)?shù)據(jù)共享(又叫做:狀態(tài)管理)是為了解決組件之間數(shù)據(jù)共享的問題。在網(wǎng)頁開發(fā)中常用的全局?jǐn)?shù)據(jù)共享方案有: Vuex 、 Redux 、 MobX 等。在小程序的官網(wǎng)中,使用了Mobx作為數(shù)據(jù)共享方案。下面介紹一些如何使用Mobx來完成數(shù)據(jù)共享。

第一步,安裝 mobx-miniprogram 和 mobx-miniprogram-bindings
npm install --save mobx-miniprogram mobx-miniprogram-bindings
第二步,創(chuàng)建 MobX Store
import { observable, action } from 'mobx-miniprogram'
export const store = observable({
  
  // 數(shù)據(jù)字段
  club: {}, 
  
  //actions
  setClubData: action(function (club) {
    this.club = club
  }),
})
第三步,在構(gòu)造器中使用
  1. 組件調(diào)用方式
    如果是組件中使用Mobx,按照以下方式在構(gòu)造器中調(diào)用,然后就可以在組件里使用store里的字段和方法。
import {
  createStoreBindings
} from 'mobx-miniprogram-bindings'
import {
  store
} from '../clubStore.js'
Component({
  behaviors: [storeBindingsBehavior],
  data: {
    someData: '...'
  },
  storeBindings: {
    store,
    fields: {
      club: () => store.club,
    },
    actions: {
      setClubData: 'setClubData'
    },
  },
  getData: function (successCallback, failedCallback) {
    wx.cloud.callFunction({
      name: 'club',
      data: {
        action: "requestClubDetails",
        id: this.pageData.clubId,
        name: this.pageData.clubName
      }
    }).then(clubResponse => {
      //調(diào)用store里的方法
      this.setClubData(clubResponse);
    }
  }
})

2)頁面中調(diào)用
如果是頁面中使用Mobx,按照以下方式在構(gòu)造器中調(diào)用,然后在頁面中就可以使用store里的字段和方法。

import {
  createStoreBindings
} from 'mobx-miniprogram-bindings'
import {
  store
} from '../clubStore.js'
Page({
  /**
   * 頁面的初始數(shù)據(jù)
   */
  data: {
    clubDetail: {},
  },
  /**
   * 生命周期函數(shù)--監(jiān)聽頁面加載
   */
  onLoad: function (options) {
    // 綁定 MobX store
    this.storeBindings = createStoreBindings(this, {
      store, // 需要綁定的數(shù)據(jù)倉庫
      fields: ['club'], // 將 this.data.club 綁定為倉庫中的 club
      actions: ['setClubData'], // 將 this.setClubData 綁定為倉庫中的 setClubData 
    });
  },
  onUnload() {
    this.storeBindings.destroyStoreBindings()
  },
  getData: function (successCallback, failedCallback) {
    wx.cloud.callFunction({
      name: 'club',
      data: {
        action: "requestClubDetails",
        id: this.pageData.clubId,
        name: this.pageData.clubName
      }
    }).then(clubResponse => {
      //調(diào)用store里的方法
      this.setClubData(clubResponse);
    }
  }
})
第四步,頁面上綁定數(shù)據(jù)

同樣,需要在clubIntroduction中按照上面的方式引用Mobx,就可以在club introduction總使用club數(shù)據(jù),達(dá)到在俱樂部中調(diào)用setClubData方法更新數(shù)據(jù),在club introduction的wxml中就可以綁定此data.

<view class="page">
  <view class="page__hd">
    <view class="page__title"></view>
  </view>
  <view class="page__bd">
    <view class="article-title">{{x}}俱樂部</view>
  
    <view class="article-content">
      <wemark md="{{club.introduction}}" link highlight type="wemark"></wemark>
    </view>
  </view>
</view>

注意
Mobx的使用需要在需要小程序基礎(chǔ)庫版本 >= 2.2.3 的環(huán)境

寫在最后

上面就介紹完了在小程序中如何進(jìn)行數(shù)據(jù),方法,屬性和代碼的共享。每種方式都有特定的使用場景。Behavior是代碼級別的重用,在組件和頁面中共享代碼,包括屬性,方法和數(shù)據(jù)。Mobx是全局?jǐn)?shù)據(jù)共享,解決了組件和頁面間數(shù)據(jù)共享,狀態(tài)更新的問題,一個(gè)組件或頁面更新數(shù)據(jù)能同步到另一個(gè)組件或者頁面。全局?jǐn)?shù)據(jù)是最簡單的數(shù)據(jù)共享方式,但最好不要把所有需要共享的數(shù)據(jù)都往全局?jǐn)?shù)據(jù)里放,避免全局?jǐn)?shù)據(jù)污染。緩存也是一種簡單有效的數(shù)據(jù)共享方式,可以同步和異步更新或者獲取緩存數(shù)據(jù),能減少服務(wù)請求次數(shù),提高小程序運(yùn)行效率。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • cholv正踐錄閱讀 202評論 0 2
  • 官宣丨國際運(yùn)動(dòng)飲料佳得樂&揭陽市羽毛球運(yùn)動(dòng)協(xié)會(huì)正式簽約! 12月30日下午,佳得樂&揭陽市羽毛球運(yùn)動(dòng)協(xié)會(huì)20...
    楊楊灑灑筆驚雷閱讀 297評論 0 0
  • 2021-1-2 23:12 意想不到,看了調(diào)取出來的數(shù)據(jù),感到自己的痛苦正是來源于低頻是的決定和結(jié)論吧? 意想不...
    陳艷霞小樹媽閱讀 582評論 0 0
  • 久違的晴天,家長會(huì)。 家長大會(huì)開好到教室時(shí),離放學(xué)已經(jīng)沒多少時(shí)間了。班主任說已經(jīng)安排了三個(gè)家長分享經(jīng)驗(yàn)。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,794評論 16 22
  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友。感恩相遇!感恩不離不棄。 中午開了第一次的黨會(huì),身份的轉(zhuǎn)變要...
    余生動(dòng)聽閱讀 10,804評論 0 11

友情鏈接更多精彩內(nèi)容