加入收藏 | 最新开课 | 最新资讯
  • 泉州浮桥企业公司办公文
  • 泉州鲤城浮桥金龙街道、
  • 泉州鲤城浮桥、中山公园
  • 泉州浮桥电脑设计培训中
  • 2018高考完了我要学电脑设
  • 泉州鲤城photoshop淘宝详情
  • 平面广告包装ps/cad/cd-201
  • 福建百科教育泉州专业a
  • 泉州浮桥金龙AUTOCAD机械零
  • Win10开机密码忘了?教你破
  • 泉州电脑设计培训班欢迎您来学习!
    泉州电脑培训班 > 在线学习 > html语言学习 >
    全部课程 专业课程 精品课程 软件课程 职业认证 学历教育 全部课程大集结

    微信小程序页面间通信的5种方式--网页设计,小程序开发

    时间:2018-03-16 00:10   来源:泉州培训班   作者:李老师15905099719   点击: 次 (责任编辑:admin)
    微信小程序页面间通信的5种方式--网页设计,小程序开发

    微信小程序页面间通信的5种方式--网页设计,小程序开发


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

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

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

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

    1. 激活对方的一个方法调用
    2. 能够向被激活的方法传递数据

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

    通信分类

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

    1. 兄弟页面间通信。如多Tab页面间通信,PageA,PageB之间通信
    2. 父路径页面向子路径页面通信,如PageA向PageC通信
    3. 子路径页面向父路径页面通信,如PageC向PageA通信

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

    1. 延迟激活,即我在PageC做完操作,等返回到PageA再激活PageA的方法调用
    2. 立即激活,即我在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属性,可能会有一些风险

    上一篇:HTML5表单验证
    下一篇:微信小程序 页面跳转传参详解-小程序开发培训