封装了一个Modal弹框作为组件使用,需要传递进来代码中标注的一些参数
项目中使用了react antd 以及 react-image-crop
需要安装8.6.4版本的 react-image-crop(截取图片插件),例如:yarn add react-image-crop@8.6.4
import React, { useEffect, useState } from 'react';
import { Modal, Button } from 'antd';
import ReactCrop from 'react-image-crop';
import 'react-image-crop/dist/ReactCrop.css';
let imageRef = null;
let videoWidth = 0;
let videoHeight = 0;
const Index = props => {
// visible 控制弹框开关 handleCancel 弹框关闭事件 handleOk 弹框点击确定 inputVideoUrl 视频的url aspect 需要截取图片的比例 例如 1 / 1
const { visible, handleCancel, handleOk, inputVideoUrl, aspect } = props;
const [src, setSrc] = useState(''); // 当前视频的图片url
const [croppedImageUrl, setCroppedImageUrl] = useState(''); // 截取之后的视频的url
const [crop, setCrop] = useState({
unit: '%',
width: 30,
aspect,
}); // 裁剪组件的基本参数
// 初始化数据
useEffect(() => {
imageRef = null;
videoWidth = 0;
videoHeight = 0;
const video = document.createElement('video');
video.setAttribute('width', '300');
video.setAttribute('height', '300');
video.setAttribute('src', inputVideoUrl);
video.setAttribute('crossOrigin', 'anonymous');
video.addEventListener('loadeddata', () => {
const { videoWidth: w, videoHeight: h } = video;
videoWidth = w;
videoHeight = h;
});
}, []);
// 手动截取视频画面作为封面
const buttonFun = () => {
const canvas = document.createElement('canvas');
const video = document.getElementById('video');
canvas.width = videoWidth;
canvas.height = videoHeight;
const context = canvas.getContext('2d');
context.clearRect(0, 0, videoWidth, videoHeight); // 清除画布内容
context.drawImage(video, 0, 0, videoWidth, videoHeight); // 将绘制的图像用img显示
setSrc(canvas.toDataURL('image/png'));
};
// 图片加载完之后的信息
const onImageLoaded = image => {
imageRef = image;
};
// 裁剪窗口的变化
const onCropChange = cropData => {
setCrop(cropData);
};
const getCroppedImg = (image, cropData) => {
const canvas = document.createElement('canvas');
const scaleX = image.naturalWidth / image.width;
const scaleY = image.naturalHeight / image.height;
canvas.width = cropData.width;
canvas.height = cropData.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(
image,
cropData.x * scaleX,
cropData.y * scaleY,
cropData.width * scaleX,
cropData.height * scaleY,
0,
0,
cropData.width,
cropData.height
);
return canvas.toDataURL('image/png');
};
const makeClientCrop = cropData => {
if (imageRef && cropData.width && cropData.height) {
const url = getCroppedImg(imageRef, cropData);
setCroppedImageUrl(url);
}
};
// 裁剪完成
const onCropComplete = cropData => {
makeClientCrop(cropData);
};
return (
<Modal
title="截取封面"
width="50%"
visible={visible}
maskClosable={false}
destroyOnClose
onCancel={handleCancel}
onOk={() => {
handleOk(croppedImageUrl);
}}
>
<div className="App">
<div>视频</div>
<div id="video_div">
<video
id="video"
width="300"
height="300"
src={inputVideoUrl}
crossOrigin="anonymous"
controls="controls"
className="video_d"
>
<track kind="captions" />
您的浏览器不支持 video 标签。
</video>
</div>
<Button type="primary" onClick={buttonFun} style={{ margin: '20px 0' }}>
作为视频封面图
</Button>
<div style={{ padding: '20px 0' }}>截取封面图</div>
<div style={{ width: 300 }}>
{src && (
<ReactCrop
src={src}
crop={crop}
ruleOfThirds
onImageLoaded={onImageLoaded}
onComplete={onCropComplete}
onChange={onCropChange}
/>
)}
</div>
<div style={{ padding: '20px 0' }}>封面图预览</div>
<div>{croppedImageUrl && <img alt="Crop" src={croppedImageUrl} />}</div>
</div>
</Modal>
);
};
export default Index;