Skip to content

useWindowSize 📐

紹介

ブラウザウィンドウのサイズ変化をリアルタイムで把握したいですか?useWindowSize はスマートなウィンドウ計測士のように、常にビューポートの幅と高さを監視しています!📏

レスポンシブレイアウト、コンポーネントサイズの動的調整、スクリーンサイズに応じたユーザー体験の最適化など、このフックによってアプリケーションがより柔軟でスマートになります!

コードデモ

基本的な使い方 🚀

最もシンプルなウィンドウサイズの監視から始めましょう:

html
<template>
  <div class="window-size-demo">
    <div class="size-display">
      <h3>現在のウィンドウサイズ 📐</h3>
      <div class="size-info">
        <div class="size-item">
          <span class="label">幅:</span>
          <span class="value">{{ width }}px</span>
        </div>
        <div class="size-item">
          <span class="label">高さ:</span>
          <span class="value">{{ height }}px</span>
        </div>
        <div class="size-item">
          <span class="label">比率:</span>
          <span class="value">{{ aspectRatio }}</span>
        </div>
      </div>
    </div>
    
    <div class="device-info">
      <h4>デバイスタイプ: {{ deviceType }} {{ deviceIcon }}</h4>
      <p>{{ deviceDescription }}</p>
    </div>
    
    <div class="resize-tip">
      <p>💡 ブラウザウィンドウのサイズを変更して、数値がリアルタイムで変化するのを確認してください!</p>
    </div>
  </div>
</template>
js
import { computed, watch } from 'vue';
import { useWindowSize } from '@vant/use';

export default {
  setup() {
    // ウィンドウサイズを取得
    const { width, height } = useWindowSize();
    
    // アスペクト比を計算
    const aspectRatio = computed(() => {
      if (height.value === 0) return '0:0';
      const ratio = width.value / height.value;
      return `${ratio.toFixed(2)}:1`;
    });
    
    // デバイスタイプを判断
    const deviceType = computed(() => {
      if (width.value < 768) return 'モバイルデバイス';
      if (width.value < 1024) return 'タブレットデバイス';
      if (width.value < 1440) return 'デスクトップデバイス';
      return '大画面デバイス';
    });
    
    // デバイスアイコン
    const deviceIcon = computed(() => {
      if (width.value < 768) return '📱';
      if (width.value < 1024) return '📱';
      if (width.value < 1440) return '💻';
      return '🖥️';
    });
    
    // デバイスの説明
    const deviceDescription = computed(() => {
      if (width.value < 768) return 'モバイルレイアウトに適しており、単列デザインを推奨';
      if (width.value < 1024) return 'タブレットレイアウトに適しており、2列デザインが可能';
      if (width.value < 1440) return 'デスクトップレイアウトに適しており、複数列デザインが可能';
      return '大画面デバイスで、より多くのコンテンツを表示できます';
    });
    
    // ウィンドウサイズの変化を監視
    watch([width, height], ([newWidth, newHeight], [oldWidth, oldHeight]) => {
      console.log(`ウィンドウサイズ変化: ${oldWidth}x${oldHeight} -> ${newWidth}x${newHeight}`);
      
      // ここでレスポンシブなロジックを実行できます
      if (newWidth !== oldWidth) {
        console.log('幅が変化したため、レイアウトを調整する必要があります');
      }
      if (newHeight !== oldHeight) {
        console.log('高さが変化したため、スクロール領域を調整する必要があります');
      }
    });
    
    return {
      width,
      height,
      aspectRatio,
      deviceType,
      deviceIcon,
      deviceDescription
    };
  }
};

レスポンシブレイアウト制御 📱

ウィンドウサイズに応じてレイアウトとスタイルを動的に調整します:

html
<template>
  <div class="responsive-layout" :class="layoutClass">
    <header class="header">
      <h1>レスポンシブレイアウトデモ</h1>
      <div class="layout-info">
        現在のレイアウト: {{ currentLayout }} ({{ width }}x{{ height }})
      </div>
    </header>
    
    <main class="main-content">
      <aside v-if="showSidebar" class="sidebar">
        <h3>サイドバー</h3>
        <nav class="nav-menu">
          <a href="#" v-for="item in menuItems" :key="item">{{ item }}</a>
        </nav>
      </aside>
      
      <section class="content">
        <div class="content-grid" :style="gridStyle">
          <div 
            v-for="item in contentItems" 
            :key="item.id"
            class="content-card"
          >
            <h4>{{ item.title }}</h4>
            <p>{{ item.description }}</p>
          </div>
        </div>
      </section>
    </main>
    
    <footer class="footer">
      <p>現在のブレークポイント: {{ currentBreakpoint }}</p>
    </footer>
  </div>
</template>
js
import { computed, watch } from 'vue';
import { useWindowSize } from '@vant/use';

export default {
  setup() {
    const { width, height } = useWindowSize();
    
    // ブレークポイントを定義
    const breakpoints = {
      xs: 0,
      sm: 576,
      md: 768,
      lg: 992,
      xl: 1200,
      xxl: 1400
    };
    
    // 現在のブレークポイント
    const currentBreakpoint = computed(() => {
      if (width.value >= breakpoints.xxl) return 'xxl';
      if (width.value >= breakpoints.xl) return 'xl';
      if (width.value >= breakpoints.lg) return 'lg';
      if (width.value >= breakpoints.md) return 'md';
      if (width.value >= breakpoints.sm) return 'sm';
      return 'xs';
    });
    
    // 現在のレイアウトタイプ
    const currentLayout = computed(() => {
      switch (currentBreakpoint.value) {
        case 'xs':
        case 'sm':
          return 'モバイルレイアウト';
        case 'md':
          return 'タブレットレイアウト';
        case 'lg':
        case 'xl':
        case 'xxl':
          return 'デスクトップレイアウト';
        default:
          return 'デフォルトレイアウト';
      }
    });
    
    // レイアウトスタイルクラス
    const layoutClass = computed(() => ({
      'layout-mobile': ['xs', 'sm'].includes(currentBreakpoint.value),
      'layout-tablet': currentBreakpoint.value === 'md',
      'layout-desktop': ['lg', 'xl', 'xxl'].includes(currentBreakpoint.value)
    }));
    
    // サイドバーを表示するかどうか
    const showSidebar = computed(() => {
      return ['md', 'lg', 'xl', 'xxl'].includes(currentBreakpoint.value);
    });
    
    // グリッドスタイル
    const gridStyle = computed(() => {
      let columns = 1;
      
      switch (currentBreakpoint.value) {
        case 'sm':
          columns = 2;
          break;
        case 'md':
          columns = 2;
          break;
        case 'lg':
          columns = 3;
          break;
        case 'xl':
        case 'xxl':
          columns = 4;
          break;
      }
      
      return {
        gridTemplateColumns: `repeat(${columns}, 1fr)`,
        gap: currentBreakpoint.value === 'xs' ? '12px' : '16px'
      };
    });
    
    // メニューアイテム
    const menuItems = ['ホーム', '製品', 'サービス', '会社概要', 'お問い合わせ'];
    
    // コンテンツアイテム
    const contentItems = Array.from({ length: 12 }, (_, i) => ({
      id: i + 1,
      title: `コンテンツカード ${i + 1}`,
      description: `これは ${i + 1} 番目のコンテンツカードの説明です。`
    }));
    
    // ブレークポイントの変化を監視
    watch(currentBreakpoint, (newBreakpoint, oldBreakpoint) => {
      console.log(`ブレークポイント変化: ${oldBreakpoint} -> ${newBreakpoint}`);
      
      // ここでブレークポイント変化のロジックを実行できます
      if (newBreakpoint === 'xs' || newBreakpoint === 'sm') {
        console.log('モバイルレイアウトに切り替え');
      } else if (newBreakpoint === 'md') {
        console.log('タブレットレイアウトに切り替え');
      } else {
        console.log('デスクトップレイアウトに切り替え');
      }
    });
    
    return {
      width,
      height,
      currentBreakpoint,
      currentLayout,
      layoutClass,
      showSidebar,
      gridStyle,
      menuItems,
      contentItems
    };
  }
};

チャートの自動調整 📊

ウィンドウサイズに応じてチャートのサイズを動的に調整します:

html
<template>
  <div class="chart-container">
    <h3>自動調整チャートデモ 📊</h3>
    
    <div class="chart-info">
      <p>ウィンドウサイズ: {{ width }} x {{ height }}</p>
      <p>チャートサイズ: {{ chartWidth }} x {{ chartHeight }}</p>
      <p>チャート比率: {{ chartRatio }}</p>
    </div>
    
    <div class="chart-wrapper" :style="chartWrapperStyle">
      <div class="chart" :style="chartStyle" ref="chartRef">
        <!-- ここに実際のチャートコンポーネントを配置できます -->
        <div class="chart-placeholder">
          <div class="chart-title">販売データチャート</div>
          <div class="chart-content">
            <div 
              v-for="bar in chartBars" 
              :key="bar.id"
              class="chart-bar"
              :style="{ height: bar.height + '%', backgroundColor: bar.color }"
            >
              <span class="bar-value">{{ bar.value }}</span>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    <div class="chart-controls">
      <button @click="toggleFullscreen" class="control-btn">
        {{ isFullscreen ? 'フルスクリーンを終了' : 'フルスクリーン表示' }}
      </button>
      <button @click="refreshChart" class="control-btn">
        チャートを更新
      </button>
    </div>
  </div>
</template>
js
import { computed, ref, watch, nextTick } from 'vue';
import { useWindowSize } from '@vant/use';

export default {
  setup() {
    const { width, height } = useWindowSize();
    const chartRef = ref(null);
    const isFullscreen = ref(false);
    
    // チャートサイズを計算
    const chartWidth = computed(() => {
      if (isFullscreen.value) {
        return width.value - 40; // マージンを確保
      }
      
      // ウィンドウ幅に基づいてチャート幅を計算
      if (width.value < 768) {
        return width.value - 32; // モバイル
      } else if (width.value < 1200) {
        return Math.min(width.value * 0.8, 800); // タブレットと小さいデスクトップ
      } else {
        return Math.min(width.value * 0.6, 1000); // 大きいデスクトップ
      }
    });
    
    const chartHeight = computed(() => {
      if (isFullscreen.value) {
        return height.value - 120; // タイトルとコントロールボタンのスペースを確保
      }
      
      // チャート幅に基づいて高さを計算し、適切なアスペクト比を維持
      return Math.min(chartWidth.value * 0.6, 400);
    });
    
    // チャート比率
    const chartRatio = computed(() => {
      const ratio = chartWidth.value / chartHeight.value;
      return `${ratio.toFixed(2)}:1`;
    });
    
    // チャートコンテナのスタイル
    const chartWrapperStyle = computed(() => ({
      width: chartWidth.value + 'px',
      height: chartHeight.value + 'px',
      margin: '0 auto',
      transition: 'all 0.3s ease'
    }));
    
    // チャートのスタイル
    const chartStyle = computed(() => ({
      width: '100%',
      height: '100%',
      border: '1px solid #e0e0e0',
      borderRadius: '8px',
      padding: '16px',
      backgroundColor: '#fff',
      boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
    }));
    
    // チャートデータ
    const chartBars = ref([
      { id: 1, value: 85, height: 85, color: '#ff6b6b' },
      { id: 2, value: 92, height: 92, color: '#4ecdc4' },
      { id: 3, value: 78, height: 78, color: '#45b7d1' },
      { id: 4, value: 96, height: 96, color: '#f9ca24' },
      { id: 5, value: 73, height: 73, color: '#6c5ce7' },
      { id: 6, value: 88, height: 88, color: '#fd79a8' }
    ]);
    
    // フルスクリーン切り替え
    const toggleFullscreen = () => {
      isFullscreen.value = !isFullscreen.value;
    };
    
    // チャートを更新
    const refreshChart = () => {
      chartBars.value = chartBars.value.map(bar => ({
        ...bar,
        value: Math.floor(Math.random() * 100) + 1,
        height: Math.floor(Math.random() * 100) + 1
      }));
    };
    
    // ウィンドウサイズの変化を監視し、チャートを再計算
    watch([width, height], async () => {
      console.log('ウィンドウサイズが変化したため、チャートサイズを再計算');
      
      // DOM 更新を待つ
      await nextTick();
      
      // ここでチャートライブラリの resize メソッドを呼び出すことができます
      if (chartRef.value) {
        console.log('チャートを再レンダリング');
      }
    });
    
    // フルスクリーン状態の変化を監視
    watch(isFullscreen, (newValue) => {
      if (newValue) {
        console.log('フルスクリーンモードに入る');
        document.body.style.overflow = 'hidden';
      } else {
        console.log('フルスクリーンモードを終了');
        document.body.style.overflow = '';
      }
    });
    
    return {
      width,
      height,
      chartWidth,
      chartHeight,
      chartRatio,
      chartWrapperStyle,
      chartStyle,
      chartBars,
      chartRef,
      isFullscreen,
      toggleFullscreen,
      refreshChart
    };
  }
};

仮想スクロールの最適化 📜

ウィンドウの高さに応じて仮想スクロールの表示項目数を最適化します:

html
<template>
  <div class="virtual-scroll-demo">
    <h3>仮想スクロールデモ 📜</h3>
    
    <div class="scroll-info">
      <p>ウィンドウの高さ: {{ height }}px</p>
      <p>表示項目数: {{ visibleCount }}</p>
      <p>総項目数: {{ totalItems }}</p>
      <p>項目の高さ: {{ itemHeight }}px</p>
    </div>
    
    <div 
      class="virtual-scroll-container"
      :style="containerStyle"
      @scroll="handleScroll"
      ref="scrollContainer"
    >
      <div class="virtual-scroll-content" :style="contentStyle">
        <div 
          v-for="item in visibleItems" 
          :key="item.id"
          class="virtual-scroll-item"
          :style="getItemStyle(item.index)"
        >
          <div class="item-content">
            <h4>アイテム {{ item.id }}</h4>
            <p>{{ item.content }}</p>
            <small>インデックス: {{ item.index }}</small>
          </div>
        </div>
      </div>
    </div>
    
    <div class="scroll-controls">
      <button @click="scrollToTop" class="control-btn">
        先頭にスクロール
      </button>
      <button @click="scrollToBottom" class="control-btn">
        末尾にスクロール
      </button>
      <button @click="addItems" class="control-btn">
        さらに項目を追加
      </button>
    </div>
  </div>
</template>
js
import { computed, ref, watch, nextTick } from 'vue';
import { useWindowSize } from '@vant/use';

export default {
  setup() {
    const { width, height } = useWindowSize();
    const scrollContainer = ref(null);
    const scrollTop = ref(0);
    const itemHeight = 80; // 各アイテムの高さ
    const totalItems = ref(1000); // 総アイテム数
    
    // ウィンドウの高さに基づいてコンテナの高さを計算
    const containerHeight = computed(() => {
      // モバイルデバイス用により多くのスペースを確保
      if (width.value < 768) {
        return Math.min(height.value * 0.6, 400);
      } else {
        return Math.min(height.value * 0.7, 500);
      }
    });
    
    // 表示アイテム数を計算
    const visibleCount = computed(() => {
      return Math.ceil(containerHeight.value / itemHeight) + 2; // バッファとして2つ多くレンダリング
    });
    
    // 開始インデックスを計算
    const startIndex = computed(() => {
      return Math.floor(scrollTop.value / itemHeight);
    });
    
    // 終了インデックスを計算
    const endIndex = computed(() => {
      return Math.min(startIndex.value + visibleCount.value, totalItems.value);
    });
    
    // 表示アイテムを生成
    const visibleItems = computed(() => {
      const items = [];
      for (let i = startIndex.value; i < endIndex.value; i++) {
        items.push({
          id: i + 1,
          index: i,
          content: `これは ${i + 1} 番目のアイテムのコンテンツです。ウィンドウサイズ: ${width.value}x${height.value}`
        });
      }
      return items;
    });
    
    // コンテナのスタイル
    const containerStyle = computed(() => ({
      height: containerHeight.value + 'px',
      overflow: 'auto',
      border: '1px solid #e0e0e0',
      borderRadius: '8px',
      backgroundColor: '#f9f9f9'
    }));
    
    // コンテンツのスタイル(スクロールをサポートするために総高さを設定)
    const contentStyle = computed(() => ({
      height: totalItems.value * itemHeight + 'px',
      position: 'relative'
    }));
    
    // アイテムのスタイルを取得
    const getItemStyle = (index) => ({
      position: 'absolute',
      top: index * itemHeight + 'px',
      left: '0',
      right: '0',
      height: itemHeight + 'px',
      padding: '12px',
      borderBottom: '1px solid #e0e0e0',
      backgroundColor: '#fff'
    });
    
    // スクロールイベントを処理
    const handleScroll = (event) => {
      scrollTop.value = event.target.scrollTop;
    };
    
    // 先頭にスクロール
    const scrollToTop = () => {
      if (scrollContainer.value) {
        scrollContainer.value.scrollTop = 0;
      }
    };
    
    // 末尾にスクロール
    const scrollToBottom = () => {
      if (scrollContainer.value) {
        scrollContainer.value.scrollTop = totalItems.value * itemHeight;
      }
    };
    
    // さらにアイテムを追加
    const addItems = () => {
      totalItems.value += 100;
      console.log(`100個のアイテムを追加、総数: ${totalItems.value}`);
    };
    
    // ウィンドウサイズの変化を監視し、仮想スクロールを再計算
    watch([width, height], async () => {
      console.log('ウィンドウサイズが変化したため、仮想スクロールのパラメータを再計算');
      
      await nextTick();
      
      // 表示アイテムを再計算
      console.log(`新しい表示アイテム数: ${visibleCount.value}`);
      console.log(`新しいコンテナの高さ: ${containerHeight.value}px`);
    });
    
    return {
      width,
      height,
      containerHeight,
      visibleCount,
      totalItems,
      itemHeight,
      visibleItems,
      containerStyle,
      contentStyle,
      scrollContainer,
      getItemStyle,
      handleScroll,
      scrollToTop,
      scrollToBottom,
      addItems
    };
  }
};

パフォーマンスモニタリングパネル ⚡

ウィンドウサイズ関連のパフォーマンスメトリクスを表示するパフォーマンスモニタリングパネルを作成します:

html
<template>
  <div class="performance-monitor">
    <h3>パフォーマンスモニタリングパネル ⚡</h3>
    
    <div class="monitor-grid">
      <div class="monitor-card">
        <h4>ウィンドウ情報 📐</h4>
        <div class="metric">
          <span class="label">現在のサイズ:</span>
          <span class="value">{{ width }} x {{ height }}</span>
        </div>
        <div class="metric">
          <span class="label">デバイスピクセル比:</span>
          <span class="value">{{ devicePixelRatio }}</span>
        </div>
        <div class="metric">
          <span class="label">スクリーンサイズ:</span>
          <span class="value">{{ screenWidth }} x {{ screenHeight }}</span>
        </div>
      </div>
      
      <div class="monitor-card">
        <h4>パフォーマンスメトリクス 📊</h4>
        <div class="metric">
          <span class="label">調整回数:</span>
          <span class="value">{{ resizeCount }}</span>
        </div>
        <div class="metric">
          <span class="label">平均間隔:</span>
          <span class="value">{{ averageInterval }}ms</span>
        </div>
        <div class="metric">
          <span class="label">最終調整:</span>
          <span class="value">{{ lastResizeTime }}</span>
        </div>
      </div>
      
      <div class="monitor-card">
        <h4>レイアウト統計 📱</h4>
        <div class="metric">
          <span class="label">モバイル:</span>
          <span class="value">{{ layoutStats.mobile }}回</span>
        </div>
        <div class="metric">
          <span class="label">タブレット:</span>
          <span class="value">{{ layoutStats.tablet }}回</span>
        </div>
        <div class="metric">
          <span class="label">デスクトップ:</span>
          <span class="value">{{ layoutStats.desktop }}回</span>
        </div>
      </div>
    </div>
    
    <div class="monitor-actions">
      <button @click="resetStats" class="action-btn">
        統計をリセット
      </button>
      <button @click="exportStats" class="action-btn">
        データをエクスポート
      </button>
    </div>
  </div>
</template>
js
import { computed, ref, watch } from 'vue';
import { useWindowSize } from '@vant/use';

export default {
  setup() {
    const { width, height } = useWindowSize();
    
    // パフォーマンス統計データ
    const resizeCount = ref(0);
    const resizeTimes = ref([]);
    const layoutStats = ref({
      mobile: 0,
      tablet: 0,
      desktop: 0
    });
    
    // デバイス情報
    const devicePixelRatio = ref(window.devicePixelRatio || 1);
    const screenWidth = ref(window.screen.width);
    const screenHeight = ref(window.screen.height);
    
    // 平均調整間隔を計算
    const averageInterval = computed(() => {
      if (resizeTimes.value.length < 2) return 0;
      
      const intervals = [];
      for (let i = 1; i < resizeTimes.value.length; i++) {
        intervals.push(resizeTimes.value[i] - resizeTimes.value[i - 1]);
      }
      
      const sum = intervals.reduce((a, b) => a + b, 0);
      return Math.round(sum / intervals.length);
    });
    
    // 最終調整時間
    const lastResizeTime = computed(() => {
      if (resizeTimes.value.length === 0) return 'なし';
      const lastTime = resizeTimes.value[resizeTimes.value.length - 1];
      return new Date(lastTime).toLocaleTimeString();
    });
    
    // 現在のデバイスタイプ
    const currentDeviceType = computed(() => {
      if (width.value < 768) return 'mobile';
      if (width.value < 1024) return 'tablet';
      return 'desktop';
    });
    
    // ウィンドウサイズの変化を監視
    watch([width, height], () => {
      // 統計データを更新
      resizeCount.value++;
      resizeTimes.value.push(Date.now());
      
      // メモリリークを避けるために記録数を制限
      if (resizeTimes.value.length > 100) {
        resizeTimes.value = resizeTimes.value.slice(-50);
      }
      
      // レイアウト統計を更新
      layoutStats.value[currentDeviceType.value]++;
      
      console.log(`ウィンドウ調整 #${resizeCount.value}: ${width.value}x${height.value}`);
    });
    
    // 統計をリセット
    const resetStats = () => {
      resizeCount.value = 0;
      resizeTimes.value = [];
      layoutStats.value = {
        mobile: 0,
        tablet: 0,
        desktop: 0
      };
      console.log('統計データがリセットされました');
    };
    
    // 統計データをエクスポート
    const exportStats = () => {
      const stats = {
        windowSize: { width: width.value, height: height.value },
        deviceInfo: {
          pixelRatio: devicePixelRatio.value,
          screenSize: { width: screenWidth.value, height: screenHeight.value }
        },
        performance: {
          resizeCount: resizeCount.value,
          averageInterval: averageInterval.value,
          layoutStats: layoutStats.value
        },
        timestamp: new Date().toISOString()
      };
      
      console.log('パフォーマンス統計データ:', stats);
      
      // データをJSONファイルとしてエクスポート
      const blob = new Blob([JSON.stringify(stats, null, 2)], {
        type: 'application/json'
      });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `window-size-stats-${Date.now()}.json`;
      a.click();
      URL.revokeObjectURL(url);
    };
    
    return {
      width,
      height,
      devicePixelRatio,
      screenWidth,
      screenHeight,
      resizeCount,
      averageInterval,
      lastResizeTime,
      layoutStats,
      resetStats,
      exportStats
    };
  }
};

API リファレンス 📚

型定義

ts
function useWindowSize(): {
  width: Ref<number>;
  height: Ref<number>;
};

戻り値

パラメータ説明
widthブラウザウィンドウのビューポート幅、ウィンドウサイズ変化に応答Ref<number>
heightブラウザウィンドウのビューポート高さ、ウィンドウサイズ変化に応答Ref<number>

実際のアプリケーションシナリオ 🎯

1. レスポンシブデザイン

  • ブレークポイント管理: ウィンドウ幅に応じて異なるレイアウトブレークポイントを切り替え
  • コンポーネントの適応: コンポーネントの表示方法とサイズを動的に調整
  • ナビゲーションの最適化: 小さなスクリーンでモバイルナビゲーションに切り替え

2. チャートの可視化

  • チャートの自動調整: コンテナサイズに応じてチャートサイズを動的に調整
  • データ密度: スクリーンサイズに応じてデータ表示密度を調整
  • インタラクションの最適化: 異なるサイズで異なるインタラクション方法を提供

3. 仮想スクロール

  • 表示アイテムの計算: コンテナの高さに基づいて仮想スクロールの表示アイテム数を計算
  • パフォーマンスの最適化: 異なるスクリーンに適応するためにレンダリング戦略を動的に調整
  • メモリ管理: ウィンドウサイズに基づいてメモリ使用量を最適化

4. ゲーム開発

  • キャンバスの適応: ゲームキャンバスのサイズを動的に調整
  • UIスケーリング: スクリーンサイズに応じてゲームUI要素を調整
  • パフォーマンス調整: ウィンドウサイズに応じてレンダリング品質を調整

ベストプラクティス 💡

1. デバウンス処理

js
import { debounce } from 'lodash-es';

// ウィンドウサイズの変化に対してデバウンス処理を行う
const debouncedResize = debounce(() => {
  console.log('ウィンドウサイズ変化処理');
}, 100);

watch([width, height], debouncedResize);

2. ブレークポイント管理

js
// 標準ブレークポイントを定義
const breakpoints = {
  xs: 0,
  sm: 576,
  md: 768,
  lg: 992,
  xl: 1200,
  xxl: 1400
};

const currentBreakpoint = computed(() => {
  const w = width.value;
  if (w >= breakpoints.xxl) return 'xxl';
  if (w >= breakpoints.xl) return 'xl';
  if (w >= breakpoints.lg) return 'lg';
  if (w >= breakpoints.md) return 'md';
  if (w >= breakpoints.sm) return 'sm';
  return 'xs';
});

3. パフォーマンスの最適化

js
// computed を使用して計算結果をキャッシュ
const isDesktop = computed(() => width.value >= 1024);
const isMobile = computed(() => width.value < 768);

// watch 内で高コストな操作を避ける
watch([width, height], async () => {
  await nextTick();
  // 必要な DOM 操作を実行
});

4. メモリ管理

js
// タイマーとイベントリスナーをクリーンアップ
onUnmounted(() => {
  // 関連リソースをクリーンアップ
  if (resizeTimer) {
    clearTimeout(resizeTimer);
  }
});

デバッグのヒント 🔧

1. サイズ変化のロギング

js
watch([width, height], ([newW, newH], [oldW, oldH]) => {
  console.log(`サイズ変化: ${oldW}x${oldH} -> ${newW}x${newH}`);
  console.log(`変化量: 幅${newW - oldW}, 高さ${newH - oldH}`);
});

2. パフォーマンスモニタリング

js
let resizeCount = 0;
let lastResizeTime = Date.now();

watch([width, height], () => {
  resizeCount++;
  const now = Date.now();
  const interval = now - lastResizeTime;
  console.log(`調整 #${resizeCount}, 間隔: ${interval}ms`);
  lastResizeTime = now;
});

3. ブレークポイントデバッグ

js
// 開発環境でブレークポイント情報を追加
if (process.env.NODE_ENV === 'development') {
  window.debugWindowSize = {
    width,
    height,
    breakpoint: currentBreakpoint
  };
}

パフォーマンスの最適化 ⚡

1. 再計算の削減

js
// computed を使用して複雑な計算をキャッシュ
const layoutConfig = computed(() => {
  // 複雑なレイアウト計算ロジック
  return calculateLayout(width.value, height.value);
});

2. バッチ更新

js
// nextTick を使用して DOM 更新をバッチ処理
watch([width, height], async () => {
  await nextTick();
  // DOM をバッチ更新
  updateLayout();
});

3. 条件付きレンダリング

js
// スクリーンサイズに基づいて条件付きでコンポーネントをレンダリング
const shouldRenderSidebar = computed(() => width.value >= 768);
const shouldRenderMobileMenu = computed(() => width.value < 768);

ブラウザの互換性 🌐

useWindowSize は標準の window.innerWidthwindow.innerHeight API に基づいています:

  • Chrome 1+
  • Firefox 1+
  • Safari 3+
  • Edge 12+
  • IE 9+

関連文書 📖

コアコンセプト

関連 Hooks

レスポンシブデザイン

パフォーマンス最適化

実際のアプリケーション

高度なトピック

Vant に基づく企業向けモバイルソリューション