小程序最佳实践-页面通信及派发通知

2,145 阅读2分钟

前言

小程序开发场景中,经常会遇到页面之间传递数据,页面通信,派发通知更新数据等业务场景,经过多次的业务迭代和各种业务场景的实现,终于找到了最佳的的实现方案,当然可能是我认为的最佳方案,记录一波方便大家对比和参考。

第一种场景

存储用户信息、设备信息、全局标记信息等

// app.js
App({
  globalData: {
    // 众多属性
  },
});

页面获取、存储、更改

// index.js
const { globalData } = getApp();
console.log(globalData);

Page({
  add() {
    globalData.userInfo = { uid: 123456 };
  },
});

通过以上方式,可以在任何页面获取 globalData 进行修改和存储内容

第二种方式

路由跳转传递参数,适用于页面和页面之间传递参数通信

// index.js
Page({
  jump() {
    wx.navigateTo({
      url: "test?id=1",
      events: {
        // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
        acceptDataFromOpenedPage: function (data) {
          console.log(data);
        },
        someEvent: function (data) {
          console.log(data);
        },
      },
      success: function (res) {
        // 通过eventChannel向被打开页面传送数据
        res.eventChannel.emit("acceptDataFromOpenerPage", { data: "test" });
      },
    });
  },
});

//test.js
Page({
  onLoad: function (option) {
    console.log(option.query);
    const eventChannel = this.getOpenerEventChannel();
    eventChannel.emit("acceptDataFromOpenedPage", { data: "test" });
    eventChannel.emit("someEvent", { data: "test" });
    // 监听acceptDataFromOpenerPage事件,获取上一页面通过eventChannel传送到当前页面的数据
    eventChannel.on("acceptDataFromOpenerPage", function (data) {
      console.log(data);
    });
  },
});

以上方式通过路由跳转的传递某些关键参数,但是通过wx.navigateTo的events属性可以进行数据的大量传递以及两个页面之间的通信。

第三种方式

通过 getCurrentPages 方法进行获取路由信息进行调用、获取、更新数据等。

//index.js
Page({
    add(){
        const testPageInfo = getCurrentPages().find(item => item.route === 'pages/test/index')
        // 获取到指定页面的路由信息,通过对当前路由信息进行调用、获取、更新数据等。
        
        // 更新某些属性
        testPageInfo.setData({a: 1})
        // 调用某些方法
        testPageInfo.change()
    }
});

第四种方式

通过订阅发布者模式进行通信和派发通知等

// utils/index.js

/**
 * eventBus 事件总线
 */
export const eventBus = {
  clients: {},
  /**
   * @method addEventListener 事件监听
   * @param {'onLoginSucess'} method 方法名
   * @param {Function} fn 回调函数
   */
  addEventListener(method, fn) {
    if (!this.clients[method]) {
      this.clients[method] = [];
    }
    this.clients[method].push(fn);
  },
  /**
   * @method triggerEventListener 事件触发
   * @param {'onLoginSucess'} method 方法名
   * @param {object} data
   */
  triggerEventListener(method, data) {
    if (!this.clients[method]) {
      log &&
        console.log(
          `========================👇 触发 eventBus 事件错误, 不存在或未注册${method}方法 👇========================\n\n`
        );
    }
    this.clients[method]?.forEach((fn) => fn(data));
  },
  /**
   * @method removeEventListener 删除事件
   * @param {'onLoginSucess'} method 方法名
   */
  removeEventListener(method) {
    if (!this.clients[method]) {
      log &&
        console.log(
          `========================👇 触发 eventBus 事件错误, 不存在或未注册${method}方法 👇========================\n\n`
        );
    }
    this.clients[method]?.pop();
  },
};


// pages/login/index.js

import { eventBus } from '~/utils/index';

Page({
  /**
   * 页面的初始数据
   */
  data: {},

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    eventBus.addEventListener("onLoginSucess", (data) => {});
  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {
    eventBus.removeEventListener("onLoginSucess");
  },
});

// pages/test/index.js

import { eventBus } from '~/utils/index';

Page({
  /**
   * 页面的初始数据
   */
  data: {},

  test(options) {
    eventBus.triggerEventListener({test: '123'});
  }
});

通过上述方式可以一次性和多个页面进行派发通知和通信交互,后续的业务场景中经常使用上述方式。

当然以上四种方式都是业务开发中常用的处理方案,具体使用哪种也要根据具体的业务逻辑来选择。如果你有更好的方式请在评论区告诉我。