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

React项目中使用QrReader无法切换前后置摄像头的问题求助

二维码扫描摄像头切换功能修复求助

这是我目标功能的示例演示。如果有人知道如何修复使其正常工作或有新的实现思路,欢迎分享。

本演示基于QrReader实现,我希望调用设备上的摄像头,并根据用户选择切换用于扫描二维码的摄像头。以下是我的代码,提前感谢各位的帮助。

import React, { useState, useRef, useEffect } from 'react';
import { QrReader } from 'react-qr-reader';
import './estilos.css';
  
function Lector() { 
  const [qrCodeData, setQrCodeData] = useState(null);
  const [activate, setActivate] = useState(false);
  const [facingMode, setFacingMode] = useState('environment');
  const qrReaderRef = useRef(null);
  const [cameras, setCameras] = useState([]);
 
  useEffect(() => {
    navigator.mediaDevices.enumerateDevices().then((devices) => {
      const videoDevices = devices.filter((device) => device.kind === 'videoinput');
      setCameras(videoDevices);
    });
  }, []);
 
  const handleQRCodeScan = (data) => {
    if (data) {
      setQrCodeData(data);
      setActivate(true);
    }
  };

  const ventana = () => {
    window.open(qrCodeData);
  };

  const ventana2 = () => {
    window.open('https://qr.primerosauxilios.online/', '_top');
  };

  const handleCameraChange = (event) => {
    setFacingMode(event.target.value);
  };

  return (
    <article className="card">
      <button onClick={ventana2} style={{ cursor: 'pointer', background: 'orange' }}>
        Generar QR
      </button>

      <select name="select" onChange={handleCameraChange}>
        {cameras.map((camera) => (
          <option key={camera.deviceId} value={camera.deviceId}>
            {camera.label || `Camera ${camera.deviceId}`}
          </option>
        ))}
      </select>

      <div className="qr-box" style={{ background: 'black', position: 'relative' }}>
        <div style={{ width: '300px', height: '300px' }}>
          <QrReader
            ref={qrReaderRef}
            style={{ width: '100%' }}
            onResult={(result, error) => {
              if (result) {
                handleQRCodeScan(result.text);
              }

              if (error) {
                console.info(error);
              }
            }}
            facingMode={facingMode}
          />
          <div
            style={{
              position: 'absolute',
              top: '50%',
              left: '50%',
              transform: 'translate(-50%, -50%)',
              border: '3px solid blue',
              width: '200px',
              height: '200px',
            }}
          ></div>
        </div>
      </div>
      <p>Resultado del QR: {qrCodeData}</p>

      {activate ? (
        <button
          onClick={ventana}
          style={{ cursor: 'pointer', background: 'black', color: 'white' }}
        >
          Abrir
        </button>
      ) : (
        <button disabled style={{ background: 'red', color: 'white' }}>
          Esperando Link
        </button>
      )}
    </article>
  );
}

export default Lector;

修复方案

核心问题

代码中facingMode的传值方式错误:当指定具体设备ID时,react-qr-reader要求传入{ exact: 设备ID }格式的对象,而非直接传入设备ID字符串。此外,部分浏览器需要先获取摄像头权限,才能返回设备的真实标签名称(如“后置摄像头”)。

修改步骤

  1. 调整摄像头切换逻辑:
    修改handleCameraChange函数,将facingMode设置为包含设备ID的对象:

    const handleCameraChange = (event) => {
      setFacingMode({ exact: event.target.value });
    };
    
  2. 确保设备标签正常显示:
    在获取设备列表前先请求摄像头权限,避免仅显示设备ID:

    useEffect(() => {
      const getDevices = async () => {
        // 请求摄像头权限,确保能获取到设备真实标签
        await navigator.mediaDevices.getUserMedia({ video: true });
        const devices = await navigator.mediaDevices.enumerateDevices();
        const videoDevices = devices.filter(device => device.kind === 'videoinput');
        setCameras(videoDevices);
      };
      getDevices();
    }, []);
    
  3. 强制组件重新挂载(可选):
    给QrReader添加key属性,值为facingMode的JSON字符串,确保切换摄像头时组件重新初始化:

    <QrReader
      key={JSON.stringify(facingMode)}
      ref={qrReaderRef}
      style={{ width: '100%' }}
      onResult={(result, error) => {
        if (result) {
          handleQRCodeScan(result.text);
        }
        if (error) {
          console.info(error);
        }
      }}
      facingMode={facingMode}
    />
    

修改后的完整代码

import React, { useState, useRef, useEffect } from 'react';
import { QrReader } from 'react-qr-reader';
import './estilos.css';
  
function Lector() { 
  const [qrCodeData, setQrCodeData] = useState(null);
  const [activate, setActivate] = useState(false);
  const [facingMode, setFacingMode] = useState('environment');
  const qrReaderRef = useRef(null);
  const [cameras, setCameras] = useState([]);
 
  useEffect(() => {
    const getDevices = async () => {
      // 请求摄像头权限,确保能获取到设备真实标签
      await navigator.mediaDevices.getUserMedia({ video: true });
      const devices = await navigator.mediaDevices.enumerateDevices();
      const videoDevices = devices.filter(device => device.kind === 'videoinput');
      setCameras(videoDevices);
    };
    getDevices();
  }, []);
 
  const handleQRCodeScan = (data) => {
    if (data) {
      setQrCodeData(data);
      setActivate(true);
    }
  };

  const ventana = () => {
    window.open(qrCodeData);
  };

  const ventana2 = () => {
    window.open('https://qr.primerosauxilios.online/', '_top');
  };

  const handleCameraChange = (event) => {
    setFacingMode({ exact: event.target.value });
  };

  return (
    <article className="card">
      <button onClick={ventana2} style={{ cursor: 'pointer', background: 'orange' }}>
        Generar QR
      </button>

      <select name="select" onChange={handleCameraChange}>
        {cameras.map((camera) => (
          <option key={camera.deviceId} value={camera.deviceId}>
            {camera.label || `Camera ${camera.deviceId}`}
          </option>
        ))}
      </select>

      <div className="qr-box" style={{ background: 'black', position: 'relative' }}>
        <div style={{ width: '300px', height: '300px' }}>
          <QrReader
            key={JSON.stringify(facingMode)}
            ref={qrReaderRef}
            style={{ width: '100%' }}
            onResult={(result, error) => {
              if (result) {
                handleQRCodeScan(result.text);
              }
              if (error) {
                console.info(error);
              }
            }}
            facingMode={facingMode}
          />
          <div
            style={{
              position: 'absolute',
              top: '50%',
              left: '50%',
              transform: 'translate(-50%, -50%)',
              border: '3px solid blue',
              width: '200px',
              height: '200px',
            }}
          ></div>
        </div>
      </div>
      <p>Resultado del QR: {qrCodeData}</p>

      {activate ? (
        <button
          onClick={ventana}
          style={{ cursor: 'pointer', background: 'black', color: 'white' }}
        >
          Abrir
        </button>
      ) : (
        <button disabled style={{ background: 'red', color: 'white' }}>
          Esperando Link
        </button>
      )}
    </article>
  );
}

export default Lector;

内容的提问来源于stack exchange,提问作者Jack K3v1n Páramo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 04:07:32