跨层调用实例集
三个层互相调用是插件系统的核心玩法。每一段都可以直接抄进自己的插件。方向总览:
| 从 ↓ / 到 → | 逻辑层 | 渲染层 | 面板层 |
|---|---|---|---|
| 逻辑层 | 本层直调(call/page;eval 抛 E_EVAL_SANDBOX) | wadLogicLayer.renderLayer.eval / page / screenshot / domSnapshot | 仅 wadLogicLayer.panelLayer.ui.toast / tools(其余走 messaging / sharedStorage) |
| 渲染层 | wadRenderLayer.logicLayer.call / emit / ui.toast | 本层(eval/dom/page) | 仅 wadRenderLayer.panelLayer.ui.toast / tools |
| 面板层 | wadPanelLayer.logicLayer.call / eval / page / storage / ui.toast | wadPanelLayer.renderLayer.eval / screenshot / domSnapshot / targets / page / ui.toast | 本层(storage/ui) |
任何方向都可以用 messaging 广播或 sharedStorage 共享状态协作 —— 这两个是「无方向」的通道。call 统一可变参:数组就是一个普通参数。
本页你将学到
- 面板 → 逻辑层 / 渲染层的全部代理用法;
- 逻辑层 → 渲染层的 eval 投递与截图;
- messaging / sharedStorage 的无方向协作模式;
- 跨层错误码的处理。
1. 面板 → 逻辑层:调用注册的函数
js
(async () => {
// 逻辑层:注册
wadLogicLayer.register('add', function (a, b) { return a + b; });
// 面板:调用(可变参,参数逐个展开)
const sum = await wadPanelLayer.logicLayer.call('add', 1, 2); // 3
})();2. 面板 → 逻辑层:执行任意 JS
js
(async () => {
const page = await wadPanelLayer.logicLayer.page(); // 逻辑层页面信息
const len = await wadPanelLayer.renderLayer.eval('document.querySelectorAll("*").length');
})();3. 面板 → 逻辑层:读页面路由
js
(async () => {
const page = await wadPanelLayer.logicLayer.page(); // { route, options }
})();4. 面板 → 逻辑层:读写 wx storage
js
(async () => {
await wadPanelLayer.logicLayer.storage.set('last-open', Date.now());
const v = await wadPanelLayer.logicLayer.storage.get('last-open');
const ks = await wadPanelLayer.logicLayer.storage.keys();
})();5. 逻辑层 → 渲染层:投递代码(fire-and-forget)
js
// 逻辑层:在页面里注入样式(多语句用 IIFE 包起来最稳)
wadLogicLayer.renderLayer.eval(`(function(){
var s = document.createElement('style');
s.textContent = '.price{filter:blur(4px)}';
document.head.appendChild(s);
})()`);6. 逻辑层 → 渲染层:拿页面信息 / 截图 / DOM 树
js
(async () => {
const info = await wadLogicLayer.renderLayer.page(); // { url, title }
const shot = await wadLogicLayer.renderLayer.screenshot(); // 经调试通道截图
const tree = await wadLogicLayer.renderLayer.domSnapshot({ tree: true });
})();7. 面板 → 渲染层:eval + DOM 检查
js
(async () => {
await wadPanelLayer.renderLayer.eval(`document.title = 'Hello WeAppDev'`);
const nodes = await wadPanelLayer.renderLayer.domSnapshot('', { tree: true });
const targets = await wadPanelLayer.renderLayer.targets();
})();8. 渲染层 → 逻辑层:call
js
(async () => {
// 渲染层:调逻辑层注册的函数(可变参)
const cfg = await wadRenderLayer.logicLayer.call('getConfig');
// 或者发个事件给本插件面板
wadRenderLayer.emit('ui-tap', { id: 'buy' });
})();9. 任意层 → 本插件面板:顶层 emit
顶层 emit 的投递范围是同插件面板(面板用 on 接收):
js
// 逻辑层发
wadLogicLayer.emit('refresh', { reason: 'manual' });
// 面板收
wadPanelLayer.on('refresh', function (d) { reload(); });10. 任意层 → 全部层:messaging 广播
js
(async () => {
// 发起方(这里在逻辑层)
await wadLogicLayer.messaging.emit('refresh', { reason: 'manual' });
// 面板与渲染层各自接收(记得过滤回声)
wadPanelLayer.messaging.on('refresh', function (d, meta) {
if (meta.from === 'logic') reload();
});
})();11. 任意层 → 全部层:sharedStorage 状态共享
js
(async () => {
// 逻辑层写
await wadLogicLayer.sharedStorage.app.set('scan-state', { done: 42, total: 100 });
// 面板 watch(渲染层同理)
wadPanelLayer.sharedStorage.app.watch('scan-state', function (v) { render(v); });
})();12. 面板 → 逻辑层注册函数 → 广播进度(完整管线)
js
(async () => {
// 逻辑层
wadLogicLayer.register('scan', function () {
var i = 0;
var t = setInterval(function () {
i += 10;
wadLogicLayer.messaging.emit('scan-progress', { pct: i });
if (i >= 100) { clearInterval(t); wadLogicLayer.sharedStorage.app.set('scan-result', { items: 42 }); }
}, 200);
return true;
});
// 面板
await wadPanelLayer.logicLayer.call('scan');
wadPanelLayer.messaging.on('scan-progress', function (d, meta) {
if (meta.from !== 'logic') return;
bar.style.width = d.pct + '%';
});
wadPanelLayer.sharedStorage.app.watch('scan-result', function (v) { show(v.items); });
})();13. 面板 ⇄ 面板(PC + 手机同时开面板)
每个面板有独立 clientId;两个面板通过 sharedStorage/messaging 自然同步,无需额外搭线。
js
// 两个面板都执行:
wadPanelLayer.messaging.on('ui-sync', function (d, meta) {
if (meta.instanceId === wadPanelLayer.clientId) return; // 过滤自己的回声
apply(d); // 对端面板的变更
});
function apply(d) { /* ... */ }14. 渲染层 → 面板:事件回传
js
// 渲染层(顶层 emit → 本插件面板)
wadRenderLayer.emit('element-selected', { selector: '.sku' });
// 面板
wadPanelLayer.on('element-selected', function (d) {
input.value = d.selector;
});15. 逻辑层:把渲染层结果存共享存储(三层接力)
js
(async () => {
// 逻辑层:拿页面标题 → 存共享 → 面板自动刷新
const info = await wadLogicLayer.renderLayer.page();
await wadLogicLayer.sharedStorage.app.set('page-title', info.title || info.url);
})();16. 定时任务:逻辑层轮询 + 三层分发
js
(async () => {
// 逻辑层(attach 后自动开始)
wadLogicLayer.onAttach(function () {
setInterval(async function () {
const st = await wadLogicLayer.renderLayer.page();
await wadLogicLayer.sharedStorage.app.set('now-page', st);
wadLogicLayer.messaging.emit('now-page', st);
}, 5000);
});
})();错误处理约定
跨层调用失败 reject 的 Error 带 .code:
js
(async () => {
try {
await wadPanelLayer.logicLayer.call('nope');
} catch (e) {
// e.message: 'Error: no function: nope'(e.code==='ERROR')/ TIMEOUT / BUS_DISCONNECTED / E_LAYER_ONLY ...
}
})();层级不可用的调用详见 三层 API 对比:注册类同步抛 E_LAYER_ONLY,查询类 Promise.reject。
下一步
- 逻辑层 / 渲染层 / 面板 UI:各层 API 全量
- messaging / sharedStorage:两个跨层通道的完整说明