Skip to content

与宿主页面通信

链接参数管「打开时是什么样」,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

给 AI 用的纯文本索引在 /llms.txt,每篇原文在 /md/ 下。