/** * camera 预览组件 * video 标签 * cordova-plugin-camera-preview 插件 */ import { useEffect, useMemo, useRef } from "react"; import ReactDOM from "react-dom"; import { IVideoConf } from "./common/CameraPreview/CameraPreviewVideo"; import { modeType } from "./common/constant"; import { ICameraPreviewerProps } from "./type"; /** * Video DOM 处理逻辑 * @param props * @returns */ export const useVideo = function (props: ICameraPreviewerProps = {}) { const { className, wrapStyle, mode = modeType.video, children, ChildrenRender, videoStyle, getContainer, } = props || {}; const isPlugin = mode === modeType.pluginCameraPreview; const rootContainerRef = useRef( (typeof getContainer === "function" ? getContainer() : getContainer) || document.body, ); const childrenContainerRef = useRef(null); const videoRef = useRef(null); /** 视频流配置 */ const videoConf = useMemo(() => { const _videoConf: IVideoConf = { /** * 默认 user 前置摄像头 * user * environment */ facingMode: "user", ...props.videoConf, }; return _videoConf; }, [props.videoConf]); // 前置摄像头镜像翻转 const transform = videoConf.facingMode !== "environment" && !isPlugin ? `rotateY(180deg)` : ""; // 初始化 DOM 结构(video + children容器) useEffect(() => { if (!(getContainer || isPlugin)) { return; } // 创建容器元素 const divBox = document.createElement("div"); divBox.className = `camera-previewer ${isPlugin ? "camera-previewer-plugin" : ""} ${className ?? ""}`; Object.assign(divBox.style, wrapStyle); if (mode === modeType.video) { // video 播放模式,创建 video 标签 const videoEl = document.createElement("video"); videoEl.className = "camera-previewer-video"; Object.assign(videoEl.style, { transform: transform, ...videoStyle, }); videoEl.setAttribute("webkit-playsinline", "true"); videoEl.setAttribute("playsinline", "true"); videoRef.current = videoEl; divBox.appendChild(videoEl); } // 渲染外部传入的 children 到 children 容器 if (children || ChildrenRender) { // 创建 children 渲染容器 const childrenEl = document.createElement("div"); childrenEl.className = `camera-previewer-children`; divBox.appendChild(childrenEl); childrenContainerRef.current = childrenEl; // TODO: 子内容更新逻辑处理; ReactDOM.render 会导致 children 内部更新无效,不触发重新渲染 ReactDOM.render(ChildrenRender ? : children, childrenContainerRef.current); } rootContainerRef.current.appendChild(divBox); return () => { // 卸载 children 渲染的React组件 if (childrenContainerRef.current) { ReactDOM.unmountComponentAtNode(childrenContainerRef.current); } // 移除相关 dom if (rootContainerRef.current) { rootContainerRef.current.removeChild(divBox); } }; }, []); return { rootContainerRef, videoRef, transform, }; }; export default useVideo;