频谱: iframe-page-comps/IframeSpectrogram.vue
Some checks failed
/ build-and-deploy-to-vercel (push) Successful in 2m46s
/ surge (push) Successful in 2m50s
/ lint-build-and-check (push) Has been cancelled
/ playwright (push) Has been cancelled

This commit is contained in:
严浩
2025-04-10 16:30:32 +08:00
parent 106eba0053
commit 89ebb71b9d
5 changed files with 238 additions and 63 deletions

View File

@ -0,0 +1,72 @@
<script setup lang="ts">
// 不再需要 props 来接收数据
// 获取 iframe 的 DOM 引用
const iframeRef = ref<HTMLIFrameElement | null>(null);
// iframe 的 src URL指向 Spectrogram.html
const src = computed(() => import.meta.env.BASE_URL + 'html-page/Spectrogram.html');
// 标记 iframe 是否已加载完成并已发送初始化指令
const isIframeInitialized = ref(false);
// iframe 加载完成后的回调
function onIframeLoad() {
console.log('[🧩] 组件 (频谱图): iframe 已加载');
// 发送初始化指令给 iframe
if (iframeRef.value?.contentWindow) {
console.log('[🧩] 组件 (频谱图): 向 iframe 发送 INIT_WIDGET 指令');
// targetOrigin 设置为 '*' 为了简单,生产环境应指定确切来源
// 可选:如果需要传递配置,可以在 INIT_WIDGET 消息中包含 config
iframeRef.value.contentWindow.postMessage({ type: 'INIT_WIDGET' /*, config: props.config */ }, '*');
isIframeInitialized.value = true; // 标记已发送初始化指令
// 发送初始数据(如果已有)
// 稍微延迟发送,给 iframe 一点时间处理 INIT_WIDGET
setTimeout(() => {
// 初始数据将通过暴露的方法发送,这里不再处理
console.log('[🧩] 组件 (频谱图): iframe 初始化完成,等待通过 ref 调用发送数据。');
}, 0);
} else {
console.error('[🧩] 组件 (频谱图): 无法访问 iframe 的 contentWindow');
}
}
// 将数据发送到 iframe 的函数
function sendDataToIframe(payload: Array<number>, time: string) {
// 添加 time 参数
// 确保 iframe 存在、其 contentWindow 可访问且已发送初始化指令
if (iframeRef.value?.contentWindow && isIframeInitialized.value) {
console.log('[🧩] 组件 (频谱图): 向 iframe 发送数据:', payload, '时间:', time);
// 使用 toRaw 获取原始数据对象
// 将时间和数据一起发送
iframeRef.value.contentWindow.postMessage({ type: 'FEED_DATA', payload: toRaw(payload), time: time }, '*');
} else {
console.warn('[🧩] 组件 (频谱图): iframe 未初始化或数据无效,无法发送 FEED_DATA 消息。');
}
}
// 不再需要监听 props
// 可选:监听来自 iframe 的 WIDGET_READY 消息以实现更精确的控制 (与星座图类似)
// onMounted(() => { ... });
// onUnmounted(() => { ... });
// function handleIframeMessage(event: MessageEvent) { ... }
// 暴露 sendDataToIframe 方法给父组件
defineExpose({
sendData: sendDataToIframe,
});
</script>
<template>
<iframe ref="iframeRef" :src="src" frameborder="0" allowfullscreen @load="onIframeLoad"></iframe>
</template>
<style scoped>
iframe {
border: none; /* 移除边框 */
width: 100%; /* 默认占满容器 */
height: 100%; /* 默认占满容器 */
}
</style>

View File

@ -0,0 +1,60 @@
<script setup lang="ts">
definePage({ meta: { title: '频谱图+瀑布图' } });
const iframeSpectrogramRef = useTemplateRef('iframeSpectrogramRef');
// 模拟生成频谱数据的函数
function generateFakeSpectrogramData(len = 200, baseLevel = -90, noiseRange = 30) {
const data = [];
for (let i = 0; i < len; i++) {
// 模拟一些峰值
let peak = 0;
if (i > len * 0.2 && i < len * 0.3) {
peak = 30 * Math.sin(((i - len * 0.2) / (len * 0.1)) * Math.PI); // 第一个峰
} else if (i > len * 0.6 && i < len * 0.75) {
peak = 20 * (1 - Math.abs(i - len * 0.675) / (len * 0.075)); // 第二个峰
}
data.push(baseLevel + Math.random() * noiseRange + peak);
}
return data;
}
// 定时更新数据以模拟实时效果
let intervalId: null | number = null;
onMounted(() => {
// 模拟: 每x秒更新一次数据并通过 ref 发送
intervalId = globalThis.setInterval(() => {
const newData = generateFakeSpectrogramData();
const newTime = new Date().toLocaleTimeString();
if (iframeSpectrogramRef.value) {
console.log('[📄] 页面:通过 ref 发送更新数据'.padEnd(120, '-'));
iframeSpectrogramRef.value.sendData(newData, newTime); // 传递动态获取的时间
} else {
console.warn('[📄] 页面:无法获取 IframeSpectrogram 组件的引用来发送更新数据');
}
console.log('[📄] 页面:更新频谱数据带时间');
}, 2000);
});
onUnmounted(() => {
// 清除定时器
if (intervalId) {
clearInterval(intervalId);
}
});
</script>
<template>
<div>
<p>频谱图+瀑布图 (通过 iframe)</p>
<div style="width: 100%; height: 400px; border: 1px solid #ccc; margin-top: 10px">
<IframeSpectrogram ref="iframeSpectrogramRef" />
</div>
</div>
</template>
<style scoped>
/* 可以添加一些页面级别的样式 */
</style>