渲染层(wadRenderLayer)
渲染层脚本(<script type="text/wad-render">)运行在当前页面的 XWeb 上下文:有 DOM,无 wx。注入是短连接(用完即断),页面切换/新 target 自动重注入;同一 target 同时只允许一个调试器,冲突会自动重试/切换。
本层 API 已拍平:直接
wadRenderLayer.eval('…'),不存在wadRenderLayer.renderLayer.eval('…')。logicLayer/panelLayer只作为跨层代理出现。
本页你将学到
wadRenderLayer顶层的 DOM / 页面 / 存储全量 API;dom.render(fn)的用法与幂等注入纪律;- 渲染层 → 逻辑层的
logicLayer.call代理; - capture / native 在渲染层的特殊行为(注册类同步抛、查询类 reject)。
eval(expr)
页面上下文同步求值。
- 签名:
eval(expr) → 结果(同步)
(async () => {
var title = wadRenderLayer.eval('document.title');
var len = await wadRenderLayer.eval('document.body.innerText.length');
})();dom.*
DOM 操作四件套,都在本层全局:
| API | 签名 | 说明 |
|---|---|---|
dom.query(s) | → Element | document.querySelector |
dom.create(t) | → Element | document.createElement |
dom.text(s, t) | → Element | 设置选择器命中元素的 textContent |
dom.render(fn) | fn(document) | 拿真实页面 document 随便操作 |
wadRenderLayer.dom.render(function (doc) {
var banner = doc.createElement('div');
banner.textContent = '已注入';
banner.style.cssText = 'position:fixed;top:6px;right:6px;z-index:99999;'
+ 'padding:4px 8px;border-radius:6px;background:rgba(0,0,0,.7);color:#fff;font-size:12px';
doc.body.appendChild(banner);
});
wadRenderLayer.dom.text('#user-name', '新文本');注意点:页面切换会重注入,dom.render 要幂等(先查有没有上一代遗留)。
page()
当前页面地址与标题。同步。
- 签名:
page() → {url, title}
var p = wadRenderLayer.page(); // {url: 'https://…', title: '…'}localStorage / sessionStorage
页面 WebView 的 Web Storage,自动加插件前缀 __wad_<id>_(见 存储)。
wadRenderLayer.localStorage.setItem('marked', '1'); // 页面 WebView 内持久
wadRenderLayer.sessionStorage.setItem('pos', '120'); // 页面关闭即消失ui.toast(t)
页面内 DOM Toast(黑底白字,2.6s 自动消失)——注意与面板/逻辑层的宿主 Toast 不同。
wadRenderLayer.ui.toast('已标记 3 张图片');on / off / emit
订阅渲染层本层事件(attach / textEditIntent…);顶层 emit 投递到本插件面板。
wadRenderLayer.on('textEditIntent', function (payload) {
if (payload.on) enableEditing(); else disableEditing();
});
wadRenderLayer.emit('element-selected', { selector: '.sku' }); // → 面板钩子糖
| 钩子 | 触发时机 |
|---|---|
onReady(fn) | 注入完成 |
onAttach(fn) | 每次注入(换页重注入也重发) |
onDetach(fn) | 仅停用 / 卸载 / 切小程序;页面导航销毁不派 |
wadRenderLayer.onAttach(function (appid) {
wadRenderLayer.log('render attached', appid, wadRenderLayer.version);
});asset(p) 与 assets.*
资产定位与加载。渲染层 assets 全量可用(含 script/css);asset(p) 是 assets.url(p) 的快捷方式。
- 签名:
asset(p) → 绝对 URL
(async () => {
await wadRenderLayer.assets.css('assets/dark.css');
var mod = await wadRenderLayer.assets.script('assets/enhance.js');
document.getElementById('css').href = wadRenderLayer.asset('assets/panel.css');
})();tools / http / messaging / sharedStorage
渲染层顶层四件套:
| 命名空间 | 语义 |
|---|---|
tools.* | 工具包,同一实现(见 tools) |
http.* | fetch 语义,默认 dataType: 'json',task 可 abort()(见 HTTP) |
messaging.* | 三层广播,emit → Promise<payload>(见 messaging) |
sharedStorage.app / global / watch | 跨层共享存储(见 sharedStorage) |
(async () => {
const res = await wadRenderLayer.http.get('https://httpbin.org/get');
await wadRenderLayer.sharedStorage.app.set('domChanged', true);
})();capture / native(渲染层特殊行为)
渲染层的 capture / native 命名空间存在但受限:
| 方法类别 | 行为 |
|---|---|
注册类:capture.intercept.* / capture.watch / native.intercept.* / native.observe.* | 同步抛 E_LAYER_ONLY |
查询类:capture.records / body / rules / addRule / removeRule / clear / native.records / get / clear | Promise.reject E_LAYER_ONLY |
try { wadRenderLayer.capture.intercept.request(function () {}); }
catch (e) { e.code === 'E_LAYER_ONLY'; } // true(同步抛)
wadRenderLayer.capture.records(10).catch(function (e) {
e.code === 'E_LAYER_ONLY'; // true(Promise.reject)
});跨层代理:logicLayer
渲染层经 wadRenderLayer.logicLayer 调逻辑层:
| API | 签名 | 说明 |
|---|---|---|
logicLayer.call(fn, ...args) | 可变参,返回 Promise | 经宿主回逻辑层执行,拿返回值 |
logicLayer.emit(name, data) | 派发逻辑层同名自定义事件(wadLogicLayer.on(name)),不是 messaging | |
logicLayer.ui.toast(t) | 派发逻辑层 wad:toast 事件;页面内 Toast 请用 wadRenderLayer.ui.toast | |
logicLayer.tools | 同本层 tools | |
logicLayer.eval / page / register / on / off / storage.* | 显式拒绝:同步抛 E_LAYER_ONLY(不是"不存在") |
// <script type="text/wad-render"> 内
wadRenderLayer.logicLayer.call('cart.count').then(function (n) {
document.querySelector('#count').textContent = n;
});注意点:page() / storage 等会被显式拒绝(E_LAYER_ONLY)——渲染层不能直接读逻辑层页面/存储,需要页面数据走 logicLayer.call 或 messaging。
跨层代理:panelLayer
| API | 说明 |
|---|---|
panelLayer.ui.toast(t) | 宿主 Toast(面板壳展示) |
panelLayer.tools | 同本层 tools |
清理纪律(必须)
页面切换会重注入,但停用/卸载不会自动还原你改过的 DOM:
// <script type="text/wad-render"> 内
var banner = null;
wadRenderLayer.dom.render(function (doc) {
banner = doc.createElement('div');
banner.textContent = 'demo';
doc.body.appendChild(banner);
});
wadRenderLayer.onDetach(function () {
// 把自己插入的东西收干净
if (banner && banner.parentNode) banner.parentNode.removeChild(banner);
banner = null;
});导航销毁不派 detach
页面导航销毁旧渲染层实例时不派 detach,随后新页面注入会重发 attach。DOM 清理要在注入时幂等处理,不能只依赖 detach。详见 生命周期与回调。
完整示例:页面元素高亮
<script type="text/wad-render">
var marked = [];
wadRenderLayer.dom.render(function (doc) {
doc.querySelectorAll('img').forEach(function (img) {
if (img.dataset.wadMarked) return;
img.dataset.wadMarked = '1';
img.style.outline = '2px solid #2FD87F';
marked.push(img);
});
});
wadRenderLayer.onDetach(function () {
marked.forEach(function (img) {
img.style.outline = '';
delete img.dataset.wadMarked;
});
marked = [];
});
</script>