资讯专栏INFORMATION COLUMN

微信小程序页面间通信的5种方式

lei___ / 1458人阅读

摘要:另外因为依赖,而可能出现读写失败,从面造成通信失败注意点页面初始化时也会触发方式二小程序同方式一一样,利用激活方法,通过读写小程序完成数据传递清队上次通信数据优点实现简单,实现理解。

微信小程序页面间通的5种方式

PageModel(页面模型)对小程序而言是很重要的一个概念,从app.json中也可以看到,小程序就是由一个个页面组成的。

如上图,这是一个常见结构的小程序:首页是一个双Tab框架PageA和PageB,子页面pageB, PageC。

让我们假设这样一个场景:首页PageA有一个飘数,当我们从PageA新开PageC后,做一些操作,再回退到PageA的时候,这个飘数要刷新。很显然,这需要在PageC中做操作时,能通知到PageA,以便PageA做相应的联动变化。

这里的通知,专业点说就是页面通信。所谓通信,u3认为要满足下面两个条件:

激活对方的一个方法调用

能够向被激活的方法传递数据

本文将根据项目实践,结合小程序自身特点,就小程序页面间通信方式作一个探讨与小结。

通信分类

按页面层级(或展示路径)可以分为:

兄弟页面间通信。如多Tab页面间通信,PageA,PageB之间通信

父路径页面向子路径页面通信,如PageA向PageC通信

子路径页面向父路径页面通信,如PageC向PageA通信

按通信时激活对方方法时机,又可以分为:

延迟激活,即我在PageC做完操作,等返回到PageA再激活PageA的方法调用

立即激活,即我在PageC做完操作,在PageC激活PageA的方法调用

方式一:onShow/onHide + localStorage

利用onShow/onHide激活方法,通过localStorage传递数据。大概逻辑如下

// pageA
let isInitSelfShow = true;

Page({
  data: {
    helloMsg: "hello from PageA"
  },

  onShow() {
    // 页面初始化也会触发onShow,这种情况可能不需要检查通信
    if (isInitSelfShow) return;

    let newHello = wx.getStorageSync("__data");

    if (newHello) {
      this.setData({
        helloMsg: newHello
      });

      // 清队上次通信数据
      wx.clearStorageSync("__data");
    }

  },

  onHide() {
    isInitSelfShow = false;
  },

  goC() {
    wx.navigateTo({
      url: "/pages/c/c"
    });
  }
});
// pageC
Page({
  doSomething() {
    wx.setStorageSync("__data", "hello from PageC");
  }
});

优点:实现简单,容易理解
缺点:如果完成通信后,没有即时清除通信数据,可能会出现问题。另外因为依赖localStorage,而localStorage可能出现读写失败,从面造成通信失败
注意点:页面初始化时也会触发onShow

方式二:onShow/onHide + 小程序globalData

同方式一一样,利用onShow/onHide激活方法,通过读写小程序globalData完成数据传递

// PageA
let isInitSelfShow = true;
let app = getApp();

Page({
  data: {
    helloMsg: "hello from PageA"
  },

  onShow() {
    if (isInitSelfShow) return;

    let newHello = app.$$data.helloMsg;

    if (newHello) {
      this.setData({
        helloMsg: newHello
      });

      // 清队上次通信数据
      app.$$data.helloMsg = null;
    }

  },

  onHide() {
    isInitSelfShow = false;
  },

  goC() {
    wx.navigateTo({
      url: "/pages/c/c"
    });
  }
});
// PageC
let app = getApp();

Page({
  doSomething() {
    app.$$data.helloMsg = "hello from pageC";
  }
});

优点:实现简单,实现理解。因为不读写localStorage,直接操作内存,所以相比方式1,速度更快,更可靠
缺点:同方式1一样,要注意globalData污染

方式三:eventBus(或者叫PubSub)方式

这种方式要先实现一个PubSub,通过订阅发布实现通信。在发布事件时,激活对方方法,同时传入参数,执行事件的订阅方法

/* /plugins/pubsub.js
 * 一个简单的PubSub
 */
export default class PubSub {
  constructor() {
    this.PubSubCache = {
      $uid: 0
    };
  }

  on(type, handler) {
    let cache = this.PubSubCache[type] || (this.PubSubCache[type] = {});

    handler.$uid = handler.$uid || this.PubSubCache.$uid++;
    cache[handler.$uid] = handler;
  }

  emit(type, ...param) {
    let cache = this.PubSubCache[type], 
        key, 
        tmp;

    if(!cache) return;

    for(key in cache) {
      tmp = cache[key];
      cache[key].call(this, ...param);
    }
  }

  off(type, handler) {
    let counter = 0,
        $type,
        cache = this.PubSubCache[type];

    if(handler == null) {
      if(!cache) return true;
      return !!this.PubSubCache[type] && (delete this.PubSubCache[type]);
    } else {
      !!this.PubSubCache[type] && (delete this.PubSubCache[type][handler.$uid]);
    }

    for($type in cache) {
      counter++;
    }

    return !counter && (delete this.PubSubCache[type]);
  }
}
//pageA
let app = getApp();

Page({
  data: {
    helloMsg: "hello from PageA"
  },

  onLoad() {
    app.pubSub.on("hello", (number) => {
      this.setData({
        helloMsg: "hello times:" + number
      });
    });
  },

  goC() {
    wx.navigateTo({
      url: "/pages/c/c"
    });
  }
});
//pageC
let app = getApp();
let counter = 0;

Page({
  doSomething() {
    app.pubSub.emit("hello", ++counter);
  },

  off() {
    app.pubSub.off("hello");
  }
});

缺点:要非常注意重复绑定的问题

方式四:gloabelData watcher方式

前面提到方式中,我们有利用globalData完成通信。现在数据绑定流行,结合redux单一store的思想,如果我们直接watch一个globalData,那么要通信,只需修改这个data值,通过water去激活调用。
同时修改的data值,本身就可以做为参数数据。

为了方便演示,这里使用oba这个开源库做为对象监控库,有兴趣的话,可以自己实现一个。

//pageA
import oba from "../../plugin/oba";

let app = getApp();

Page({
  data: {
    helloMsg: "hello from PageA"
  },

  onLoad() {
    oba(app.$$data, (prop, newvalue, oldValue) => {
      this.setData({
        helloMsg: "hello times: " + [prop, newvalue, oldValue].join("#")
      });
    });
  },

  goC() {
    wx.navigateTo({
      url: "/pages/c/c"
    });
  }
});
//pageC
let app = getApp();
let counter = 0;

Page({
  doSomething() {
    app.$$data.helloTimes = ++counter;
  }
});

优点:数据驱动,单一数据源,便于调试
缺点:重复watch的问题还是存在,要想办法避免

方式五:通过hack方法直接调用通信页面的方法

直接缓存页面PageModel, 通信时,直接找到要通信页面的PageModel,进而可以访问通信页面PageModel所有的属性,方法。简直不能太cool,感谢小组内小伙伴发现这么amazing的方式。
有人肯定会问了,怎么拿到这个所有的PageModel呢。其它很简单,每个页面有onLoad方法,我们在这个事件中,把this(即些页面PageModel)缓存即可,缓存时用页面路径作key,方便查找。那么页面路径怎么获取呢,答案就是page__route__这个属性

// plugin/pages.js 
// 缓存pageModel,一个简要实现
export default class PM {
  constructor() {
    this.$$cache = {};
  }

  add(pageModel) {
    let pagePath = this._getPageModelPath(pageModel);

    this.$$cache[pagePath] = pageModel;
  }

  get(pagePath) {
    return this.$$cache[pagePath];
  }
  
  delete(pageModel) {
    try {
      delete this.$$cache[this._getPageModelPath(pageModel)];
    } catch (e) {
    }
  }

  _getPageModelPath(page) {
    // 关键点
    return page.__route__;
  }
}
// pageA
let app = getApp();

Page({
  data: {
    helloMsg: "hello from PageA"
  },

  onLoad() {
    app.pages.add(this);
  },

  goC() {
    wx.navigateTo({
      url: "/pages/c/c"
    });
  },
  
  sayHello(msg) {
    this.setData({
      helloMsg: msg
    });
  }
});
//pageC

let app = getApp();

Page({
  doSomething() {
    // 见证奇迹的时刻
    app.pages.get("pages/a/a").sayHello("hello u3xyz.com");
  }
});

优点:一针见血,功能强大,可以向要通信页面做你想做的任何事。无需要绑定,订阅,所以也就不存在重复的情况
缺点:使用了__route__这个hack属性,可能会有一些风险

以上!

原文地址: http://www.u3xyz.com/#/detail/20

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/82288.html

相关文章

  • 信小程序开发中二三事之网易云信IMSDK DEMO

    摘要:传统的网页编程采用的三剑客来实现,在微信小程序中同样有三剑客。观察者模式不难实现,重点是如何在微信小程序中搭配其特有的生命周期来使用。交互事件传统的事件传递类型有冒泡型与捕获型,微信小程序中自然也有。 本文由作者邹永胜授权网易云社区发布。 简介为了更好的展示我们即时通讯SDK强悍的能力,网易云信IM SDK微信小程序DEMO的开发就提上了日程。用产品的话说就是: 云信 IM 小程序 S...

    weij 评论0 收藏0
  • 信小程序 使用filter过滤器几方式

    摘要:与之间通过桥协议通信包括调用指令和各种事件,涉及消息序列化跨线程通信与。一个小程序可以有多个,页面间切换动画比更流畅。业务无法直接控制。 showImg(http://upload-images.jianshu.io/upload_images/326507-e81e06b2cb7187e9.jpeg?imageMogr2/auto-orient/strip%7CimageView2/...

    godruoyi 评论0 收藏0
  • vue和信小程序区别、比较

    摘要:相比之下,小程序的钩子函数要简单得多。一生命周期先贴两张图生命周期小程序生命周期相比之下,小程序的钩子函数要简单得多。的钩子函数在跳转新页面时,钩子函数都会触发,但是小程序的钩子函数,页面不同的跳转方式,触发的钩子并不一样。 前言 写了vue项目和小程序,发现二者有许多相同之处,在此想总结一下二者的共同点和区别。相比之下,小程序的钩子函数要简单得多。 写了vue项目和小程序,发现二者有...

    yck 评论0 收藏0
  • vue和信小程序区别、比较

    摘要:相比之下,小程序的钩子函数要简单得多。一生命周期先贴两张图生命周期小程序生命周期相比之下,小程序的钩子函数要简单得多。的钩子函数在跳转新页面时,钩子函数都会触发,但是小程序的钩子函数,页面不同的跳转方式,触发的钩子并不一样。 前言 写了vue项目和小程序,发现二者有许多相同之处,在此想总结一下二者的共同点和区别。相比之下,小程序的钩子函数要简单得多。 写了vue项目和小程序,发现二者有...

    mcterry 评论0 收藏0
  • 前端面试题总结(js、html、小程序、React、ES6、Vue、算法、全栈热门视频资源)

    摘要:并总结经典面试题集各种算法和插件前端视频源码资源于一身的文档,优化项目,在浏览器端的层面上提升速度,帮助初中级前端工程师快速搭建项目。 本文是关注微信小程序的开发和面试问题,由基础到困难循序渐进,适合面试和开发小程序。并总结vue React html css js 经典面试题 集各种算法和插件、前端视频源码资源于一身的文档,优化项目,在浏览器端的层面上提升速度,帮助初中级前端工程师快...

    li21 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<