You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中页面宽高变化时实时检测设备类型(含横屏、平板)的实现问题

设备类型检测实现方案

原方案问题根因

  • useEffect依赖项不符合React响应式规则:window.innerWidth/window.innerHeight等浏览器原生属性不属于React管理的响应式状态,值发生变更时React无法感知,因此检测逻辑只会在组件挂载时执行一次,不会随视口变化更新
  • 检测逻辑维度不足:仅通过是否支持触屏区分两类设备,没有加入UA规则、尺寸规则区分平板,也没有加入横竖屏判断逻辑,无法覆盖需求指定的四类场景

具体实现方案

1. 优化视口变化监听逻辑

通过resize事件监听视口变化,搭配防抖逻辑减少高频触发带来的性能损耗,无需将window属性加入useEffect依赖。

2. 扩展检测逻辑覆盖四类场景

检测逻辑按分层规则判断:

  1. 非触屏设备直接归为桌面端
  2. 触屏设备通过UA匹配+视口尺寸判断:UA包含平板标识、或视口最小边≥768px的设备归为平板
  3. 剩余触屏设备判定为移动端,再通过视口宽高判断横竖屏:宽度大于高度则为移动端横屏,否则为移动端

完整代码示例

import { useState, useEffect } from 'react';

// 防抖函数,可根据需求调整等待时长
const debounce = (func, wait = 200) => {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
};

const DeviceDetectDemo = () => {
  const [deviceType, setDeviceType] = useState('');

  const deviceDetector = () => {
    let hasTouchScreen = false;
    if ("maxTouchPoints" in navigator) {
      hasTouchScreen = navigator.maxTouchPoints > 0;
    } else if ("msMaxTouchPoints" in navigator) {
      hasTouchScreen = navigator.msMaxTouchPoints > 0;
    } else {
      const mQ = matchMedia("(pointer:coarse)");
      if (mQ && mQ.media === "(pointer:coarse)") {
        hasTouchScreen = !!mQ.matches;
      } else if ("orientation" in window) {
        hasTouchScreen = true;
      } else {
        const UA = navigator.userAgent;
        hasTouchScreen =
          /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
          /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA);
      }
    }

    // 非触屏设备直接判定为桌面端
    if (!hasTouchScreen) {
      setDeviceType("Desktop");
      return;
    }

    const UA = navigator.userAgent;
    const minViewportSide = Math.min(window.innerWidth, window.innerHeight);
    // 判定是否为平板
    const isTablet = /\b(iPad|Android|Tablet|PlayBook|Silk)\b/i.test(UA) 
      && !/\b(Mobile|phone)\b/i.test(UA)
      || minViewportSide >= 768;
    
    if (isTablet) {
      setDeviceType("Tablet");
      return;
    }

    // 移动端判断横竖屏
    const isLandscape = window.innerWidth > window.innerHeight;
    setDeviceType(isLandscape ? "MobileLandscape" : "Mobile");
  };

  useEffect(() => {
    // 初始化执行一次
    deviceDetector();
    // 绑定防抖后的监听函数
    const debouncedDetect = debounce(deviceDetector);
    window.addEventListener('resize', debouncedDetect);
    // 组件卸载时清理事件
    return () => {
      window.removeEventListener('resize', debouncedDetect);
    };
  }, []);

  return <div>当前设备类型:{deviceType}</div>;
};

export default DeviceDetectDemo;

可选优化点

  • 可根据业务实际调整平板的尺寸阈值,部分业务会将900px作为平板与移动端的分界
  • 可根据业务面向的设备范围补充更多UA匹配规则,提升小众设备的识别准确率
  • 横竖屏判断可补充window.orientationAPI做老旧设备的兼容兜底
  • 不想手动实现基础逻辑的场景,可使用主流React工具库内置的媒体查询Hook简化监听代码,无需手动绑定resize事件

内容的提问来源于stack exchange,提问作者Chrissisbeast

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 00:57:03