本文总结了小程序原生开发中的几种通信方式,可以覆盖大多数使用场景
组件通信
组件间的通信官方文档中也有相应的介绍
方法一:props & triggerEvent
父组件 → 子组件:父组件通过WXML将props传递给子组件,通过监听事件获取子组件数据
子组件 → 父组件:子组件通过properties拿到父组件传过来的数据,通过triggerEvent触发事件向父组件传递数据
/** 父组件 */
// parent-component.ts
Component({
...
data: {
parentData: 'parent'
},
methods: {
onChildChange(data) {
console.log('child data:', data) // 子组件传过来的数据
}
}
...
})
// parent-component.wxml
...
<child-component value="{{parentData}}" bind:on-change="onChildChange" />
...
/** 子组件 */
// child-components.ts
Component({
...
properties: {
value: String // 父组件传过来的数据
}
data: {
childData: 'child'
},
lifetimes: {
ready() {
this.triggerEvent('on-change', { data: this.data.childData })
},
},
...
})
方法二:selectComponent
父组件还可以通过 this.selectComponent 方法获取子组件实例对象,这样就可以直接访问组件的任意数据和方法。
/** 父组件 */
// parent-component.ts
Component({
...
methods: {
getChildInstance(data) {
const child = this.selectComponent('#my-component'); // 获取 id 为 my-component 的子组件实例
console.log('child:', child) // 可以通过child获取到子组件的所有数据并且可以直接调用子组件方法
child.childFunction() // 调用子组件方法
}
}
...
})
// parent-component.wxml
...
<child-component id="my-component" /> // 注意, 这里给子组件设置的id或class,父组件才能通过selectComponent获取到该子组件
...
/** 子组件 */
// child-components.ts
Component({
...
data: {
childData: 'child'
},
methods: {
childFunction() {
console.log('this is child function')
},
},
...
})
直接让父组件获取到子组件的所有方法和实例会让父子组件耦合在一起,代码很容易出现bug。比如子组件删除时还需要去看看他的方法和数据是否被父组件调用,十分的不好维护,所以这里不建议直接把子组件的所有方法和数据暴露给父组件,那有没有办法自定义输出指定的数据和方法呢?当然有!
使用内置 behavior: wx://component-export可以自定义 selectComponent 返回的数据(从基础库版本 2.2.3 开始提供支持)。使用该 behavior 时,自定义组件中的 export 定义段将用于指定组件被 selectComponent 调用时的返回值。
/** 父组件 */
// parent-component.ts
Component({
...
methods: {
getChildInstance(data) {
const child = this.selectComponent('#my-component'); // 获取 id 为 my-component 的子组件实例
console.log('child:', child) // 可以通过child获取到子组件的所有数据并且可以直接调用子组件方法
child.childFunction() // 调用子组件方法
}
}
...
})
// parent-component.wxml
...
<child-component id="my-component" /> // 注意, 这里给子组件设置的id或class,父组件才能通过selectComponent获取到该子组件
...
/** 子组件 */
// child-components.ts
Component({
behaviors: ['wx://component-export'],
export() {
return {
childData: 'childData',
childFunction() {
console.log('this is child function')
}
}
}
...
})
跨页面通信
页面间的传值使用场景主要为 路由切换 和 跨多个页面共享数据
方法一:通过全局状态传值
全局管理要共享的数据,让每一个页面都可以获取到想要的数据,具体有以下几种实现方式:
- 使用状态管理库如redux
- 通过globalData共享
- 通过localStorage共享(wx.setStorageSync/wx.getgetStorageSync) - 不建议
这种方法适用于数据本身就需要全局共享,供多个页面使用。如果是跳转路由获取上一个页面的值这么做会十分麻烦,不仅会让全局状态混乱,而且在使用前要确保数据的正确赋值
方法二:通过eventChannel在跳转路由时实现页面间的通信
通过 wx.navigateTo 中的events和eventChannel实现页面间的通信
父页面 → 子页面:wx.navigeteTo中的succes回调中可以获取到eventChannel(res.eventChannel),通过eventChannel.emit可以向子页面发送事件。通过wx.navigeteTo的events属性可以监听子页面传回来的事件
子页面 → 父页面:在子组件的onLoad中使用this.getOpenerEventChannel()可以获取到eventChannel,通过eventChannel可以监听父页面的事件和发送事件给父页面
// 父页面
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' })
}
})
//子页面
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)
})
}
})