深色模式
与宿主页面通信
链接参数管「打开时是什么样」,postMessage 管「打开之后要变」——改筛选条件、重新取数、换主题,都不用刷新 iframe。
所有消息都带 source 标记:报表发出的是 conch-report,宿主发来的是 conch-report-host。两边都按这个标记过滤,页面上别的库发的消息不会被当成指令。
报表 → 宿主
js
window.addEventListener('message', (e) => {
if (e.origin !== 'https://report.example.com') return
const msg = e.data
if (!msg || msg.source !== 'conch-report') return
// ...
})type | 什么时候发 | 带什么 |
|---|---|---|
ready | 报表打开并渲染完 | id 报表 id、title 报表名、version 看的是哪一版 |
height | 内容高度变了(首次渲染、切筛选条件、窗口变宽变窄) | height 内容高度,单位 px |
params | 筛选条件变了(人在筛选栏上改的,或宿主发 setParams 改的) | params 当前全部条件的值 |
js
// 报表发出来的消息长这样
{ source: 'conch-report', type: 'ready', id: 'r260922123456', title: '门店经营看板', version: 'v3' }
{ source: 'conch-report', type: 'height', height: 872 }
{ source: 'conch-report', type: 'params', params: { month: '2026-08', store: ['S001'] } }三件典型的事:
- 收到
height就调 iframe 高度,页面里不会出现第二条滚动条。 - 收到
ready再把加载动画去掉,或者记一笔埋点。 - 收到
params把条件写回宿主自己的地址栏,用户刷新页面还能回到同一个筛选状态。
宿主 → 报表
js
frame.contentWindow.postMessage(
{ source: 'conch-report-host', type: 'setParams', params: { month: '2026-07' } },
'https://report.example.com', // 生产上写具体域名,别用 '*'
)type | 作用 | 带什么 |
|---|---|---|
setParams | 改筛选条件,改完自动重新取数 | params:条件 id → 值,只写要改的那几个 |
refresh | 按当前条件重新取一次数 | 无 |
setTheme | 换设计令牌 | tokens:令牌名 → 值,见外观与主题 |
值的写法和链接参数一致,只是这里用真正的 JS 类型,不用拼字符串:
js
{ month: '2026-08' } // 月份
{ range: ['2026-01-01', '2026-03-31'] } // 日期区间:[起, 止]
{ amount: [100, 500] } // 数字区间:[小, 大]
{ store: ['S001', 'S002'] } // 多选
{ keyword: null } // null = 不限发早了会丢
iframe 还没加载完时发的消息没人接。等 ready 到了再发,或者在 iframe.onload 之后发。
两边接起来的样子
js
const REPORT_ORIGIN = 'https://report.example.com'
const frame = document.getElementById('report')
let ready = false
const pending = []
window.addEventListener('message', (e) => {
if (e.origin !== REPORT_ORIGIN) return
const msg = e.data
if (!msg || msg.source !== 'conch-report') return
if (msg.type === 'height') frame.style.height = msg.height + 'px'
if (msg.type === 'ready') { ready = true; pending.splice(0).forEach(send) }
if (msg.type === 'params') syncToAddressBar(msg.params)
})
function send(msg) {
if (!ready) { pending.push(msg); return }
frame.contentWindow.postMessage({ source: 'conch-report-host', ...msg }, REPORT_ORIGIN)
}
// 宿主自己的筛选器联动报表
document.getElementById('month').addEventListener('change', (e) => {
send({ type: 'setParams', params: { month: e.target.value } })
})用不上 postMessage 的场合
- 小程序 web-view:不支持这套消息,只能用链接参数,条件要变就换
src。 sandbox属性写死的 iframe:加了sandbox就必须带上allow-scripts allow-same-origin,否则报表里的脚本跑不起来,消息也发不出来。要用导出功能再加allow-downloads。
