外部の可視化ダッシュボード(例:Grafana)をVueアプリケーション内にiframeとして埋め込む際、動的に変化するURLの取得やiframe内のDOM要素に対する操作(非表示・削除・追加)が必要になるケースがある。これらの操作は同源ポリシーにより制限されるため、事前にバックエンド側でプロキシ設定を行い、iframeのドメインを現在のVueアプリケーションと同一オリジンにする必要がある。
動的iframe URLの取得
iframeのsrcは初期ロード時にAPIから取得し、Vueのリアクティブなプロパティにバインドする。iframeが読み込まれた後、contentWindow.location.hrefを参照することで現在のURLを取得できる。
<template>
<iframe
ref="dashboardFrame"
:src="currentUrl"
frameborder="0"
style="width: 100%; height: 100%"
@load="onIframeLoaded"
/>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const dashboardFrame = ref(null);
const currentUrl = ref('');
// 初期URLはAPIから取得済みと仮定
currentUrl.value = 'https://your-proxied-grafana-endpoint/';
const getCurrentIframeUrl = () => {
if (dashboardFrame.value) {
try {
return dashboardFrame.value.contentWindow.location.href;
} catch (e) {
console.error('iframe URLの取得に失敗:', e);
return null;
}
}
};
</script>
iframe内部DOMへの操作
iframeのロード完了後に、一定間隔で内部DOMの存在を確認し、特定の要素を操作する。以下は、GrafanaのUI要素を非表示にし、カスタムボタンを挿入する例である。
const pollInterval = ref(null);
const onIframeLoaded = () => {
if (pollInterval.value) clearInterval(pollInterval.value);
pollInterval.value = setInterval(() => {
try {
const doc = dashboardFrame.value?.contentDocument ||
dashboardFrame.value?.contentWindow?.document;
if (!doc) return;
// 特定のツールバーボタンを非表示
const toolbarButtons = doc.querySelectorAll('.css-kg0g4j-toolbar-button');
toolbarButtons.forEach(btn => {
btn.style.visibility = 'hidden';
});
// カスタム操作ボタンを挿入
const targetContainer = doc.querySelector('.css-exd1zr');
if (targetContainer && targetContainer.children.length === 4) {
const getBtn = doc.createElement('button');
getBtn.textContent = '現在のURLを取得';
getBtn.className = 'custom-toolbar-btn';
getBtn.onclick = () => {
const url = getCurrentIframeUrl();
console.log('現在のiframe URL:', url);
};
const setBtn = doc.createElement('button');
setBtn.textContent = '現在のクエリをデフォルトに設定';
setBtn.className = 'custom-toolbar-btn';
setBtn.onclick = () => {
// デフォルトURL設定ロジック
};
targetContainer.insertBefore(getBtn, targetContainer.firstChild);
targetContainer.insertBefore(setBtn, targetContainer.firstChild);
// 不要な元の要素を削除
const elementsToRemove = Array.from(targetContainer.children).slice(0, 2);
elementsToRemove.forEach(el => el.remove());
clearInterval(pollInterval.value);
pollInterval.value = null;
}
} catch (error) {
console.warn('iframe DOM操作中にエラー発生(通常は読み込み中):', error.message);
}
}, 300);
};
onMounted(() => {
if (dashboardFrame.value) {
onIframeLoaded();
}
});
上記の実装では、setIntervalを用いてiframe内のDOMが完全にレンダリングされるまでポーリングを行い、目的の要素が存在するタイミングで操作を実行している。操作完了後はタイマーをクリアし、不要な処理を回避する。