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

ReactJS中如何检测iPhone iOS的「请求移动/桌面网站」模式?

解决iOS设备「请求移动/桌面网站」模式检测与下拉组件适配问题

问题分析

当前仅通过操作系统类型渲染下拉组件:iOS用Select,其他系统用Form.Control。但iOS切换到「请求桌面网站」模式时,Select组件无法正常显示选项,移动模式下则无此问题。核心原因是桌面模式下iOS的UA会伪装成MacOS,原检测逻辑仍判定为iOS,但实际桌面环境下Select组件适配出现异常。

解决方案

新增检测逻辑区分iOS的移动模式和桌面请求模式,具体思路:

  • iOS桌面请求模式的UA包含Macintosh,同时设备仍支持触摸(navigator.maxTouchPoints > 0)
  • 结合原操作系统检测逻辑,精准判断当前设备模式

步骤1:扩展设备模式检测函数

修改原系统检测函数,新增iOS桌面模式的判断:

function getDeviceMode() {
  const userAgent = navigator.userAgent || navigator.vendor || window.opera;
  
  // Windows Phone 优先判断(UA含Android)
  if (/windows phone/i.test(userAgent)) {
    return "Windows Phone";
  }

  if (/android/i.test(userAgent)) {
    return "Android";
  }

  // iOS 原生移动模式检测
  if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
    return "iOS Mobile";
  }

  // iOS 请求桌面网站模式检测:伪装成Mac但支持触摸
  if (/Macintosh/.test(userAgent) && navigator.maxTouchPoints > 0) {
    return "iOS Desktop";
  }

  return "unknown";
}

步骤2:在React组件中应用检测结果

在组件中调用检测函数(结合useEffect确保客户端执行,避免SSR报错),根据结果选择对应组件:

import { useEffect, useState } from 'react';

// 组件内部状态与逻辑
const [deviceMode, setDeviceMode] = useState("unknown");

useEffect(() => {
  setDeviceMode(getDeviceMode());
}, []);

// 渲染部分
<Form.Group>
  <Form.Label>
    <FormattedMessage id="GENERAL.DURATION" />
  </Form.Label>
  {deviceMode === "Android" || deviceMode === "Windows Phone" || deviceMode === "unknown" || deviceMode === "iOS Desktop" ? (
    <Form.Control
      as="select"
      name="duration"
      value={durationHour}
      onChange={(e) => setDurationHour(e.target.value)}
    >
      <option value="0" label="0" />
      <option value="1" label="1" />
      <option value="2" label="2" />
      <option value="3" label="3" />
      <option value="4" label="4" />
      <option value="5" label="5" />
      <option value="6" label="6" />
      <option value="7" label="7" />
      <option value="8" label="8" />
      <option value="9" label="9" />
      <option value="10" label="10" />
      <option value="11" label="11" />
      <option value="12" label="12" />
    </Form.Control>
  ) : (
    <Select
      styles={{
        menu: provided => ({ ...provided, zIndex: 9999 })
      }}
      options={optionsHour}
      value={{ label: durationHour, value: durationHour }}
      onChange={(e) => { setDurationHour(e.value) }}
    />
  )}
</Form.Group>

关键说明

  • navigator.maxTouchPoints用于区分真实Mac设备(通常为0)和iOS桌面请求模式(仍支持触摸,值>0)
  • 使用useState+useEffect确保检测逻辑仅在客户端执行,避免服务端渲染时navigator不存在的错误
  • 当检测到iOS Desktop模式时,渲染Form.Control替代Select,解决下拉选项不显示的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 19:36:16