本文作者:空空叶
出处: bbs.quickapp.cn/forum.php?m…
背景
快应用版本: 1020
在使用web组件进行快应用与网页间的通信的时候,有这几个发现:
1、运行'npm run watch'时会提示web组件不支持message事件,但实际上是支持的(只是提示上的小问题)
2、快应用发信息到网页,与网页发信息到快应用,用的方法名都是postMessage,但数据格式并不一致,使用起来不方便
3、消息会丢失(比如网页端消息处理函数还没执行到就给网页发信息等情况)
4、网页给快应用发信息时,快应用发送给网页的信息才会带回
特点
因此,这里花了点力气,做了个辅助的库,特点:
1、消息有序发送
2、消息不会丢失,保证到达
3、消息不会接收多次(去重)
4、消息分类型,类似事件的监听机制,更加方便
快应用端代码
快应用里,新建一个channel.js文件,内容:
<template>
<web id="web" src="xxx" @message="{{onMessage}}"></web>
</template>
<script>
import Channel from './channel'
export default {
channel: null,
onInit() {
this.channel = new Channel(this, 'web')
//通道监听
this.channel.on('type1', function (data) {
//处理收到的数据
})
//发送信息
this.channel.sendMsg('type2', {
//数据
})
},
onMessage(param) {
this.channel.onMsg(param)
},
}
</script>复制代码
网页端代码
网页端js(可以新建一个js或复制到script脚本里):
/**
* (在html端,实际上一个页面只能new一个通道)
*
* 通道,用来与html进行可靠的通信
*
* 1. 有序
* 2. 回传与ack机制,保证到达
* 3. id验证机制,去重
*
* @param logger {Function} 日志记录器,可为null
* @param timeout {Number} 超时时间,超时后会重试,单位ms,默认1000
*/
var Channel = function (logger, timeout) {
timeout = timeout || 1000
if (!logger) logger = () => {}
var that = this
//消息id生成器
that.idGenerator = 0
//消息发送队列
that.sendQueue = [
// {
// data: {},
// resolve: Object,
// },
]
//***列表
that.listeners = {
// type: [listener1, listener2],
}
//当前接收的消息id
that.receivedId = 0
/**
* @param type {String} 消息类型
* @param data {Object} 消息内容
* @return {Promise}
*/
that.sendMsg = function (type, data) {
var resolve;
var promise = new Promise(resolve_ => resolve = resolve_)
that.sendQueue.push({
data: {
pType: 'msg',
id: ++that.idGenerator,
type: type,
data: data,
},
resolve
})
return promise
}
/**
* 监听
* @param type 消息类型
* @param callback 回调
*/
that.on = function (type, callback) {
var typeListeners = that.listeners[type] || []
that.listeners[type] = typeListeners
typeListeners.push(callback)
}
/**
* 收到消息时调用(设置为onmessage的处理函数)
*/
that.onMsg = function (message) {
logger('[收到消息]' + message)
var {pType, id, type, data} = JSON.parse(message)
if (pType === 'ack') {//ack
if (id === that.idGenerator) {//是当前的ack,有效,删除元素
var nowPackets = that.sendQueue.splice(0, 1);
that.valid_(nowPackets.length === 1)
nowPackets[0].resolve()
}
} else if (pType === 'msg') {//正常消息
if (id === that.receivedId + 1) {//是下个准备接收的包,有效
//更新缓存值
that.receivedId++
//处理
var typeListeners = that.listeners[type] || []
logger('[处理消息]类型: ' + type + ' 处理器数量: ' + typeListeners.length)
for (var i = 0; i < typeListeners.length; i++) {
try {
typeListeners[i](data)
} catch (e) {
logger('[处理异常]'+JSON.stringify(e))
}
}
//响应ack
that.send_({
pType: 'ack',
id,
})
}
} else {//没有pType,忽略
return
}
}
/**
* 发包
*/
that.send_ = function (packet) {
var str = JSON.stringify(packet)
system.postMessage(str)
logger('[发送消息]' + str)
}
/**
* 下个包
*/
that.next_ = function () {
if (that.sendQueue.length > 0) {
that.send_(that.sendQueue[0].data)
}
}
/**
* 验证
*/
that.valid_ = function (bool, errMsg) {
if (!bool) {
throw new Error(errMsg || 'Valid Fail!')
}
}
//计时器: 不断重试发送包
setInterval(function () {
that.next_()
}, timeout)
//计时器: ping
//(必须不断地ping,因此html不发请求到app,那么app发送给html的消息就不会过来,蛋疼)
setInterval(function () {
that.send_({})
}, 200)
//对接
system.onmessage = that.onMsg
}
复制代码
网页端使用方法(参考):
var channel = new Channel()
//通道监听
channel.on('type1', function (data) {
//处理收到的数据
})
//发送信息
channel.sendMsg('type2', {
//数据
})
复制代码
最 后
1、快应用发信息到网页,官方文档写的信息格式是messageString,但这个在文档里并没说格式是怎样的,在官方的demo里可以看到注释的代码里格式是{message: 'xxx'}
2、网页端的日志不好显示
相关阅读:
写在最后
在去年的开发者大赛征文中,我们通过多个社区联合活动收集了很多优质文章,有入坑指南、开源项目、开发模板、常见问题总结等多个方面,这些内容为很多开发者提供了参考,感谢大家的支持和参与,今年的我们的征文活动还在继续,感兴趣的开发者可以点阅读原文查看详情哦!
在去年的开发者大赛征文中,我们通过多个社区联合活动收集了很多优质文章,有入坑指南、开源项目、开发模板、常见问题总结等多个方面,这些内容为很多开发者提供了参考,感谢大家的支持和参与,今年的我们的征文活动还在继续,感兴趣的开发者可以到以下查看详情
bbs.quickapp.cn/forum.php?m…
快应用生态平台——赋能开发者 拓展场景未来
转载于:https://juejin.im/post/5d0743a451882569821e5f56