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

如何关闭react-qr-reader摄像头?解决IonModal关闭后摄像头仍激活问题

问题

我用react-qr-reader组件做了一个QR码扫描模态框,模态框能正常创建和扫描,但关闭IonModal后,摄像头还一直处于激活状态,只是不再检测QR码了。

我想知道怎么停用摄像头?

查资料的时候看到有人说在关闭函数里加ref.current.stopCamera(),但我没法定义ref,因为QrReader组件的类型IntrinsicAttributes & QrReaderProps里没有ref属性。

那我该怎么引用这个组件?用ref.current.stopCamera()来停摄像头是不是正确的做法?

附上我的代码:

export const ScannerModal: React.FC<ScannerProps> = ({ triggerID, handleScannedNode }) => {
  const modal = useRef<HTMLIonModalElement>(null);
  const scannerConstraints: MediaTrackConstraints = {

  }

  function onDissMiss(event: CustomEvent<OverlayEventDetail>){
    console.log(event)
    close()
  }

  function handleScan(result: string){
    close()
    handleScannedNode(result)
  }

  async function close(){
    console.log("closing")
    const stream = await navigator.mediaDevices.getUserMedia({
      audio: false,
      video: true,
  });
  stream.getTracks().forEach(function (track) {
      track.stop();
      track.enabled = false;
  });
  //ref.current.stopCamera()
  }

  return (
  <>
  <IonModal trigger={triggerID} onWillDismiss={onDissMiss} ref={modal}>
    <IonTitle>Scanne einen QR-Code</IonTitle>
    <IonPage>
    <QrReader constraints={scannerConstraints} ref={}
        onResult={(result, error) => {
          if (!!result) {
            handleScan(result?.getText());
          }

          if (!!error) {
            //console.info(error);
          }
        }}/>
    </IonPage>
  </IonModal>
  </>
  );
};

我尝试这样引用QrReader:

const reader = useRef(null);

<QrReader constraints={scannerConstraints} ref={reader}
        onResult={(result, error) => {
          if (!!result) {
            handleScan(result?.getText());
          }

          if (!!error) {
            //console.info(error);
          }
        }}/>

得到的错误是:

Property 'ref' does not exist on type 'IntrinsicAttributes & QrReaderProps'.
解决方案

1. 给QrReader添加ref支持

react-qr-reader默认没暴露ref,你可以用React.forwardRef包装一层组件,让它能接收ref:

import React, { forwardRef, useRef } from 'react';
import { QrReader } from 'react-qr-reader';

// 包装组件,转发ref
const QrReaderWithRef = forwardRef((props, ref) => {
  return <QrReader {...props} ref={ref} />;
});

之后在你的ScannerModal里用这个包装后的组件,就能正常用ref了:

export const ScannerModal: React.FC<ScannerProps> = ({ triggerID, handleScannedNode }) => {
  const readerRef = useRef<any>(null);
  const modal = useRef<HTMLIonModalElement>(null);
  const scannerConstraints: MediaTrackConstraints = {};

  function onDissMiss(event: CustomEvent<OverlayEventDetail>){
    close();
  }

  function handleScan(result: string){
    close();
    handleScannedNode(result);
  }

  async function close(){
    // 优先调用组件自带的stopCamera方法
    if (readerRef.current) {
      readerRef.current.stopCamera();
    }
    // 兜底:手动停止所有视频轨道,防止组件方法失效
    try {
      const streams = await navigator.mediaDevices.enumerateDevices();
      for (const device of streams) {
        if (device.kind === 'videoinput') {
          const stream = await navigator.mediaDevices.getUserMedia({
            video: { deviceId: device.deviceId }
          });
          stream.getTracks().forEach(track => track.stop());
        }
      }
    } catch (err) {
      // 忽略已停止的设备报错
    }
  }

  return (
    <>
      <IonModal trigger={triggerID} onWillDismiss={onDissMiss} ref={modal}>
        <IonTitle>Scanne einen QR-Code</IonTitle>
        <IonPage>
          <QrReaderWithRef 
            constraints={scannerConstraints} 
            ref={readerRef}
            onResult={(result, error) => {
              if (result) {
                handleScan(result.getText());
              }
            }}
          />
        </IonPage>
      </IonModal>
    </>
  );
};

2. 为什么之前的方法没用?

你之前调用navigator.mediaDevices.getUserMedia会重新请求一个新的摄像头流,而不是获取当前正在使用的流,所以停止这个新流对原来的扫描器流没用。改用enumerateDevices遍历所有视频设备,停止对应流才是正确的。

3. 确认摄像头已关闭

关闭模态框后,看浏览器地址栏的摄像头图标是否消失,或者在浏览器设置里检查该网站的摄像头权限状态,确认是否已停止使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 20:25:14