1. 程式人生 > >讓微信小程式頁面之間的通訊不在變得困難

讓微信小程式頁面之間的通訊不在變得困難

一個開始

小程式開發者總會碰到各種頁面之間的通訊問題,實現方式也五花八門,比如...

場景還原

首先這是一個電商小程式。

有這樣一個需求:

  1. 首頁某個地方要展示購物車商品數量。
  2. 當我在其他頁面加購了商品,首頁數量重新整理。

實現方式

  1. 方式一:onShow直接請求介面
Page({
    onShow() {
        // ...一些邏輯
        
        // 後端請求新的購物車數量
        this.requestCartNum();
    }
})

 

不足: 每次onShow都要請求介面,浪費資源。

  1. 方式二:globalData儲存購物車數量,onShow中做重新整理

  

// 主頁.js
Page({
    onShow() {
        // 在globalData獲取到購物車資料
        let num = globalData.cartNum;
        if (num !== this.data.cartNum) {
            this.setData({
                cartNum: num,
            });
        }
    }
});

// 加購頁.js
Page({
    // 加購後改變globalData的值
    cartAdd(num) {
        globalData.cartNum = globalData.cartNum + num;
    }
})

 

 

  1. 方式三:加購後獲取首頁例項,呼叫首頁方法
// 首頁.js
Page({
    onCartAdd(num) {
        this.setData({
            cartNum: this.data.cartNum + num,
        });
    },
});

// 加購頁.js
Page({
    onCartAdd(num) {
        // 加購後獲取到首頁的例項,呼叫首頁onCartAdd方法
        let pages = getCurrentPages();
        let curPage = pages[0];
        curPage.onCartAdd(num);
    }
})

 

不足:不確定能不能準確拿到首頁的例項,如果換做其他頁面就很難複用

  1. 方法四:事件訂閱與釋出
// 首頁.js
Page({
    onLoad() {
        // 首頁監聽事件
        this.$bus.on('cart_add', (num) => {
            this.setData({
                cartNum: this.data.cartNum + num,
            })
        })
    }
})

// 加購頁.js

Page({
    // 加購成功後觸發cart_add事件
    onCartAdd(num) {
        this.$bus.emit('cart_add', num);
    }
})

 

此方法用事件系統,訂閱釋出模式去做的處理。

以上幾種方法中最優解決方案是方法四,利用事件的訂閱與釋出,邏輯清晰相容性好。但是都不可避免的不足是:每一個需要動態顯示購物數量的頁面都需要新增相同的邏輯程式碼。

狀態管理方案

單頁應用中最常用的就是元件之間的通訊,由此誕生了不同的狀態儲存方案: react用redux, vue用vuex。他們的思路都是類似的。都有一個核心 store 儲存著一切要管理的狀態。

那麼,其他框架可以,小程式也可以。以redux為例,實現一套簡單的狀態管理方案。

wxdux的實現

使用前提:有redux基礎

wxdux 類似與redux,以action來描述觸發的行為,reducer來描述state的變化。

1. 小程式入口中註冊

註冊store並新增到globalData中去

import {createStore} from './wxdux/index';
import reducer from './reducer';

const store = createStore(reducer);

App({
    globalData: {
        store,
    },
});

 

2. reducer實現

寫法與redux類似,功能也類似。

const userReducer = (state = {}, action) => {
    // ...
}

const postReducer = (state = [], action) => {
    // ...
};

const reducers = {
    user: userReducer,
    posts: postReducer,
};

export default reducers;

 

3. 頁面中使用wxdux

connect方法會將小程式頁面例項與wxdux連線起來,必須提供$useState方法,該方法接收state,返回該頁面所需要的state

import {connect} from './wxdux/index';

Page(connect({
    data: {
        sex: '男',
    },
    onLoad() {
        // ...
    },
    $useState(state) {
        return {
            name: state.name,
        },
    },
}))

 

4. wxml中使用name

<view>{{name}}</view>

 

5. 觸發store更新

使用dispatch方法,該方法接收一個物件作為引數,該物件必須包含type欄位表示action的型別,wxdux會根據此action更新state並且重新整理所有使用name的檢視

import {dispatch} from './wxdux/index';

Page(connect({
    // 某點選事件觸發,更新姓名為“張三”
    onClick() {
        const updateName = {
            type: 'update_name',
            name: '張三'
        };
        dispatch(updateName);
    }
}))

 

最後

github