Skip to content

useWindowSize 📐

介绍

想要实时掌握浏览器窗口的尺寸变化吗?useWindowSize 就像一个智能的窗口测量师,时刻监控着视口的宽度和高度!📏

无论是响应式布局、动态调整组件大小,还是根据屏幕尺寸优化用户体验,这个 Hook 都能让你的应用变得更加灵活和智能!

代码演示

基础用法 🚀

让我们从最简单的窗口尺寸监控开始:

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 '适合平板布局,可以使用两列设计';
      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構建的企業級移動端解決方案