Vue 3 のComposition API と Element Plus の Tab コンポーネントを組み合わせて ECharts を利用する際、以下のような警告が出力されることがあります。ただし、グラフ自体は正しく描画されているケースがあります。
Can’t get DOM width or height. Please check dom.clientWidth and dom.clientHeight.
They should not be 0. For example, you may need to call this in the callback of window.onload.
現象の解析
デバッグログを確認すると、ライフサイクルフックである onMounted が期待以上に複数回実行されるか、またはドメインのサイズ計算が 0 になるタイミングが存在することが判明しました。
初期マウント時は要素の幅や高さを取得できていたものの、条件によって再実行された際(例:タブ切り替えなど)、コンテナの物理的なサイズが未確定で 0 として返却される挙動が確認されています。
対応方針 1: ランタイムチェックの実装
初期化処理を実行する前に、対象エレメントが実際に画面に展開され、有効なサイズを持っているかを判断条件に追加することで回避可能です。
import { ref, onMounted } from 'vue';
const chartContainerRef = ref<HTMLElement | null>(null);
onMounted(() => {
const container = chartContainerRef.value;
// DOM の実寸法が確保されていることを確認してから初期化を実行
if (container && container.clientWidth > 0) {
renderChart(container);
}
});
// グラフ描画ロジック(仮)
function renderChart(dom: HTMLElement) {
// ECharts インスタンス生成処理などをここに記述
}
根本原因と構造的アプローチ
この問題は、el-tabs コンポーネント内で el-tab-pane を v-for ループを使用して動的生成している際に発生しやすくなります。非アクティブなタブ内の要素は表示されていないため、ブラウザ側でサイズ情報が 0 として扱われることが多いためです。
代替案 A: レイアウト構成の変更
el-tab-pane の内部配置を避け、絶対位置指定(position: absolute)を用いて視覚的には同様のレイアウトに保ちつつ、初期化プロセスを干渉させないようにします。
<template>
<el-tabs v-model="activeTabName" type="card">
<el-tab-pane
v-for="pane in tabList"
:key="pane.name"
:label="pane.label"
:name="pane.name"
/>
<div class="chart-overlay" style="width: 100%; height: 100%;">
<div ref="mainChartContainer"></div>
</div>
</el-tabs>
</template>
代替案 B: 条件付きレンダリングの活用
ループを使わない場合や、特定の条件のみで描画が必要な場合は、v-if により適切なタイミングで DOM を生成するアプローチも有効です。
<el-tab-pane label="PCS 管理" name="pcs-view">
<!-- パネルがアクティブになった時点でのみインスタンスを生成 -->
<MyChartComponent v-if="currentTab === 'pcs-view'" />
</el-tab-pane>