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

如何为网页相机组件实现类似手机相机的对焦功能?

相机组件优化:添加对焦功能+解决画面过宽问题

一、解决画面过宽问题

部分手机出现视频画面过宽,主要是因为未指定视频的宽高约束,且video元素样式未做适配。可以从以下两点调整:

1. 优化媒体流约束

在获取相机流时,为video参数添加宽高比、分辨率限制,优先匹配设备的理想拍摄参数,避免画面拉伸:

const constraints = {
  audio: false,
  video: {
    facingMode: "environment",
    // 优先使用16:9的宽高比,适配大部分手机
    aspectRatio: 1.77777778, // 即16/9
    // 设置分辨率范围,优先取设备支持的最优值
    width: { ideal: 1280, max: 1920 },
    height: { ideal: 720, max: 1080 }
  }
};

2. 设置video元素样式

给video元素添加CSS,确保它在容器内按比例显示,不会超出或拉伸:

.video-container {
  position: relative;
  width: 100%;
  max-width: 400px; /* 可根据需求调整最大宽度 */
  margin: 0 auto;
}

.video-container video {
  width: 100%;
  height: auto;
  object-fit: cover; /* 保持比例裁剪多余部分,避免拉伸 */
}

二、实现点击对焦功能

借助WebRTC的媒体轨道约束,监听video元素的点击事件,将点击位置转换为相机的对焦坐标,实现类似手机相机的点击对焦效果:

完整修改后的React代码

import { useRef, useEffect } from 'react';

const CameraComponent = () => {
  const videoRef = useRef(null);
  const streamRef = useRef(null); // 保存流对象,用于后续修改轨道约束

  useEffect(() => {
    const constraints = {
      audio: false,
      video: {
        facingMode: "environment",
        aspectRatio: 1.77777778,
        width: { ideal: 1280, max: 1920 },
        height: { ideal: 720, max: 1080 },
        // 开启自动对焦支持,部分设备需要显式声明
        focusMode: "auto"
      }
    };

    navigator.mediaDevices
      .getUserMedia(constraints)
      .then((stream) => {
        videoRef.current.srcObject = stream;
        streamRef.current = stream;
        videoRef.current.play();
      })
      .catch((error) => {
        console.error("相机获取失败:", error);
      });

    // 点击对焦事件处理
    const handleVideoClick = (e) => {
      if (!streamRef.current) return;

      const video = videoRef.current;
      // 获取点击位置相对于video元素的坐标
      const rect = video.getBoundingClientRect();
      const x = (e.clientX - rect.left) / rect.width;
      const y = (e.clientY - rect.top) / rect.height;

      // 获取视频轨道
      const videoTrack = streamRef.current.getVideoTracks()[0];
      if (!videoTrack) return;

      // 设置对焦约束:点击位置的相对坐标(0-1范围)
      const constraints = {
        focusMode: "manual",
        pointOfInterest: { x, y }
      };

      // 应用约束,实现点击对焦
      videoTrack.applyConstraints(constraints)
        .catch((err) => {
          console.warn("对焦失败(设备可能不支持):", err);
          // 如果设备不支持手动对焦, fallback到自动对焦
          videoTrack.applyConstraints({ focusMode: "auto" });
        });
    };

    videoRef.current?.addEventListener('click', handleVideoClick);

    return () => {
      // 清理事件监听和流
      videoRef.current?.removeEventListener('click', handleVideoClick);
      const videoElement = videoRef.current;
      if (videoElement && videoElement.srcObject) {
        const stream = videoElement.srcObject;
        stream.getTracks().forEach((track) => track.stop());
      }
    };
  }, []);

  return (
    <div className="video-container">
      <video ref={videoRef} autoPlay playsInline />
    </div>
  );
};

export default CameraComponent;

关键说明

  • 点击坐标转换:将点击的绝对坐标转换为video元素的相对坐标(0到1之间),这是相机API要求的pointOfInterest参数格式。
  • 设备兼容性处理:部分旧设备可能不支持手动对焦,所以在applyConstraints失败时,自动 fallback到自动对焦模式。
  • playsInline属性:添加该属性可以避免iOS设备上视频自动全屏播放,保证在组件内正常显示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 17:30:22