上回说到,魔卡塔防的好友数据已经乖乖躺在了微信托管后台,Layout 引擎也准备就绪。但真正让你抓狂的问题来了:主域点下“击杀榜”按钮,子域像没听见一样毫无反应;好不容易画出来了,手指戳上去又像戳在空气上。这块“消息桥梁”的搭建,直接决定了排行榜是死是活。今天就把主域与子域的通信协议和排行榜点击交互两座大山一并拆解。
微信开放数据域是一个完全隔离的 JavaScript 沙箱,和主域不能共享变量,也不能互相调用函数。它们之间唯一的沟通渠道,是一条单向消息管道:主域能向子域发消息,子域却无法主动“回话”。
这条管道由两个 API 构成:主域的 postMessage 和 子域的 wx.onMessage。消息通信是单向的,只能主域向子域发消息,子域不能向主域发消息。在子域中用 wx.onMessage 进行监听,在主域中发送消息给子域。
const openDataContext = wx.getOpenDataContext(); openDataContext.postMessage({ command: 'killsBtn_click' });
wx.onMessage((data) => { switch (data.command) { case 'killsBtn_click': friendList.sort((a, b) => b.kills - a.kills); break; case 'towerBtn_click': friendList.sort((a, b) => b.towers - a.towers); break; } renderRanking(mockData, data.command);});
这里有一个坑:子域不能直接调用 wx.postMessage 向主域发送消息。通信通了,数据也有了,排行榜画出来了——可你用手指戳屏幕上的“击杀榜”按钮,什么都没发生。
问题出在渲染模式上。 开放数据域的 Canvas(sharedCanvas)不会直接显示在屏幕上,而是作为一张纹理被主域渲染到某个 Sprite 上。
因此,子域无法像主域那样直接给某个视图节点绑定点击事件,只能全局监听触摸事件,再通过触摸点的屏幕坐标来判断用户是否点击了某个“虚拟按钮”。
wx.onTouchEnd((res) => { const touch = res.changedTouches[0]; if (touch) { const touchX = touch.clientX; const touchY = touch.clientY; //...根据坐标点范围判断是否点击按钮, //之后向主域发送按钮点击消息 } });
最后来看一个细节:点击“击杀榜”和“防御塔榜”按钮时,按钮背景色要随之切换,给用户明确的视觉反馈。
魔卡塔防的做法是在 renderRanking 函数中,根据 data.command 的值动态修改 Layout 引擎中对应元素的样式:
const killsBtn = Layout.getElementsById('killsBtn_click')[0];const towerBtn = Layout.getElementsById('towerBtn_click')[0];if (data.command === 'killsBtn_click') { killsBtn.style.backgroundColor = 'rgba(58, 123, 213, 0.7)'; towerBtn.style.backgroundColor = 'rgba(10, 15, 35, 0.8)';}Layout.layout(sharedContext); // 重新绘制
核心思路是:通过消息传递当前激活的榜单类型,在渲染时动态修改样式,最后重新调用 Layout.layout() 刷新画布。
排行榜上的每一次点击,都是一次主域与子域的隔空对话。把通信打通了,交互写顺了,排行榜才真正“活”起来。如果你正在用 Cocos 开发塔防、跑酷或消除类小游戏,排行榜是拉高留存和裂变率的利器。魔卡塔防已完整实现好友击杀榜与防御塔榜,欢迎扫码体验,看看你的好友排第几!你在子域实现点击交互时,遇到过坐标偏移还是事件穿透?或者有其他更头疼的坑?欢迎在评论区聊聊,我会逐一回复解答。