小程序页面通信解决方案

1,869 阅读3分钟

小程序页面通信

解决方案有很多,本地缓存、全局变量、手写订阅发布。本文着重介绍另一个解决方案,就是暂存当前页面的执行上下文,然后在另一个页面调用。

github地址

简介

主要是想解决小程序跨页面通信的问题,我想用一种最简单,最优雅,并且让用户可以很方便的使用的小工具。

安装

将 store.js 文件放在 utils 文件夹( 可以是任意文件夹 )下即可,然后引入文件。

引入

import store from "path/store.js"

使用

推荐的使用流程是这样的,比如 b 页面需要用到 a 页面里的数据。

  1. 先在 a 页面引入 store 然后在 onload 方法里使用 store.addData(this, "a") 来将当前页面的执行上下文加载到 store 的数据池里。
  2. 在 b 页面引入 store ,然后就可以在 b 页面通过 store.a.数据名 来获取相应数据的值,也可以通过 store.a.数据名 = "balabala" 来给相应的数据赋值,这里注意,这样的赋值方式是响应式的,不需要通过 setData 函数来赋值就可以达到效果。(暂未实现 setData 方式赋值,推荐使用直接赋值)

方法简介

  • 添加页面数据

    store.addData( context, name )
    

    参数说明:

    • context

      执行上下文,也就是当前页面的 this

    • name

      命名当前页面,也就是在别的页面取值的时候 store.name.属性,默认值为当前页面的路径

  • 移除页面数据

    store.removeData( name )
    

    参数说明

    • name

      希望删除的页面数据的名字

  • 获取数据

    let value = store.页面name.属性
    

    这样既可获取数据,后台是用代理封装了数据池,从而方便用户使用

  • 修改数据

    store.页面name.属性 = value
    

    这样赋值即可,后台使用的依然是封装的 setData

  • 检测属性是否存在

    property in store.页面name
    

    代码

    /**
       * @author xiaoheng
       * @time 2019/8/1
       * @github https://github.com/xiaoheng21
       * @tip 还在找工作,有机会望告知,坐标北京
       */
    /**
       * 状态管理类
       * @constructor 构造函数
       * @_data  内部数据,用来保存页面数据
       * @addData 添加页面数据的方法
       * @removeData 移除不需要的页面数据,减小内存压力
       */
      class Store {
        constructor() {
          this._data = {};
        }
      
        /**
         * 向数据池里添加数据
         * @param { Object<this> } context 保存当前页面的执行上下文,也就是当前页面的 this
         * @param { String } name 当前页面数据的名字,用于在别的页面读取数据,默认值为当前页面的路径
         */
        addData(context, name) {
          // 如果传了 name 就用传过来的,如果未传就用页面路径
          let routeName = name ? name : context.route;
          //设置代理,用于简化操作
          let proxyContext = new Proxy(context, {
            // 获取数据,如果数据在外层,返回外层数据
            get: function(context, property) {
              if (property in context) {
                return context[property];
              } else {
                // 如果外层找不到数据, 就在 "this.data" 里找,若有,返回数据
                if (property in context.data) {
                  return context.data[property];
                } else {
                  //若没有,报错
                  console.error(`${name}页面没有此属性`);
                }
              }
            },
            // 改变数据, 封装 "this.setData", 简化操作
            set: function(context, property, value) {
              context.setData({
                [property]: value
              });
              return true;
            },
            // 判断数据是否存在
            has: function(context, property) {
              return property in context.data;
            }
          });
          // 将代理对象添加进数据池
          this._data[routeName] = proxyContext;
        }
      
        /**
         * 从数据池里移除页面数据
         * @param { String } name 需要移除的页面的名字
         */
        removeData(name) {
          if (name in this._data) {
            delete this._data[name];
          } else {
            console.error(`希望删除的属性不存在`);
          }
        }
      }
      
      // 创建单例对象,全局共享一个数据池
      const store = new Store();
      
      // 创建代理, 私有化 _data, 简化用户操作, 提高安全性
      let proxyStore = new Proxy(store, {
        // 若访问的属性为 add remove 函数, 直接返回函数
        get: function(store, property) {
          if (property in store) {
            return store[property];
          } else {
            // 若访问的数据为页面数据, 则返回页面代理对象
            if (property in store._data) {
              return store._data[property];
            } else {
              // 若没有页面信息, 报错
              console.error("访问的页面数据未载入数据池");
            }
          }
        }
      });
      
      export default proxyStore;