视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
小程序数据通信方法大全(推荐)
2020-11-27 21:58:37 责编:小采
文档


本文论述的是子或孙向父传递数据的情况,自下而上

相信大家平时在小程序开发中肯定遇到过页面或者组件之间的数据通信问题,那小程序数据通信都有哪些方式呢?如何选择合适的通信方式呢?这就是本文要讨论的重点。

关系划分

在讨论都有哪些数据通信方式之前,我们先来定义一下,小程序页面、组件之间都有哪些关系。我总结了一下,大概分为以下3类:

  1. 父子关系
  2. 兄弟关系
  3. 爷孙关系

不同的关系里面,不同角色之间有可能是页面,也有可能是组件,接下来我们就一个个来揭示如何进行数据通信。

父子关系

父子关系一般主要就是两种情况:

父为页面,子为组件 父为组件,子为组件

这种关系可能是频率出现最高的了,毕竟大部分小程序页面都是以小而美为主,可能没有分的太细,碰到这种情况,我们可以通过在父页面监听子组件触发的事件来完成数据通信。

方法一

<!-- 当自定义组件触发“myevent”事件时,调用“onMyEvent”方法 -->
<component-tag-name bindmyevent="onMyEvent" />

<!-- 在自定义组件中 -->
<button bindtap="onTap">点击这个按钮将触发“myevent”事件</button>
Component({
 methods: {
 onTap() {
 const myEventDetail = {} // detail对象,提供给事件监听函数
 const myEventOption = {} // 触发事件的选项
 this.triggerEvent('myevent', myEventDetail, myEventOption)
 }
 }
})

 

兄弟关系

兄弟关系同样分为两种情况:

  1. 兄弟间都是页面
  2. 兄弟间都是组件

兄弟间都是页面

这种关系指的就是,同层次间的页面,简单理解其实就是页面之间的跳转,那从页面A跳到页面B,页面B如何修改页面A的数据呢?

方法二

页面生命周期里面都有 onShow``onHide 方法,通过 localStorage 或者 globalData 作为数据中转,进入到不同页面时,在前一个页面 onShow 里面取出数据,在后一个页面 onShow 里面存储数据,具体做法如下:

<!--app.js-->
App({
 globalData: { count: 0 },
});

<!--页面A-->
onShow(){
 let countValue = wx.getStorageSync('count');
 
 <!--globalData的方式-->
 let countValue = getApp().globalData.count;
 <!---->
 
 if(countValue){
 this.setData({
 count:countValue
 })
 }
 
 <!--globalData的方式 清除数据-->
 getApp().globalData.count = null
 <!---->
}
onHide(){
 wx.removeStorageSync('count') 
}

<!--页面B-->
onShow(){
 <!--globalData的方式-->
 getApp().globalData.count = 1
 <!---->
 
 wx.setStorageSync('count',1);
}

 

爷孙关系

爷孙关系算是数据通信中最复杂的了,因为不是直系传递,若是通过 方法一 来监听,那就需要通过多级传递事件了,如果节点比较深,可想而知代码是得多难理解且难以维护。

我们可以通过全局创建一个事件总栈 EventBus ,利用这个 EventBus 来订阅发布事件,也就是我们经常使用的 发布订阅模式 ,那在小程序里面如何实现呢?

方法三

<!--第一步:实现一个事件总栈类-->
class EventBus {
 constructor() {
 this.bus = {};
 }
 // on 订阅
 on(type, fun) {
 if (typeof fun !== 'function') {
 console.error('fun is not a function');
 return;
 }
 (this.bus[type] = this.bus[type] || []).push(fun);
 }
 // emit 触发
 emit(type, ...param) {
 let cache = this.bus[type];
 if (!cache) return;
 for (let event of cache) {
 event.call(this, ...param);
 }
 }
 // off 释放
 off(type, fun) {
 let events = this.bus[type];
 if (!events) return;
 let i = 0,
 n = events.length;
 for (i; i < n; i++) {
 let event = events[i];
 if (fun === event) {
 events.splice(i, 1);
 break;
 }
 }
 }
}
module.exports = EventBus;

<!--第二步:在app.js文件中引入-->
import EventBus from './common/event-bus/index.js';
App({
 eventBus: new EventBus(),
});

<!--第三步:在父页面或者父组件中监听某个事件-->
onLoad: function(options) {
 app.eventBus.on('add-count', this.addCount);
}
onUnload: function(options) {
 app.eventBus.off('add-count', this.addCount);
}


<!--第四步:在子组件里面触发事件-->
methods: {
 addCount() {
 app.eventBus.emit('add-count');
 }
}

除此之外,还有一种方式,我们可以在每个页面 onLoad 周期里面将该页面的 pageModel 对象缓存起来,之后在孙辈组件里面拿到祖孙的页面对象,从而触发祖孙页面对象对应的方法。

<!--第一步:实现一个pageModel,用来缓存页面对象-->
class PageModel {
 constructor() {
 this.pageCache = {};
 }

 add(page) {
 let pagePath = this._getPageModelPath(page);
 this.pageCache[pagePath] = page;
 }

 get(path) {
 return this.pageCache[path];
 }

 delete(page) {
 delete this.pageCache[this._getPageModelPath(page)];
 }
 <!--这一段代码是关键,存储的是__route__属性-->
 _getPageModelPath(page) {
 return page.__route__;
 }
}

export default PageModel ;

<!--第二步:app.js中引入-->
import PageModel from './common/page-model/index.js';

App({
 pageModel: new PageModel(),
});

<!--第三步:页面onLoad周期里缓存页面-->
onLoad: function(options) {
 app.pageModel.add(this);
}

<!--第四步:子孙获取祖辈方法-->
methods: {
 addCount() {
 app.pageModel.get('pages/communicate/index').addCount();
 }
}

下载本文
显示全文
专题