react 使用原生input开发拍照上传功能
实现的思路首先就是创建一个自定义上传的样式,点击自定义上传的时候,通过useRef,获取到input的click事件,这样就可以在onChange里面拿到文件流传递给后端了。
1、创建自定义的上传样式
<div>
<img
src={imgSrc}
onClick={() => inputRef.current.click()}
/>
<span>点击上传</span>
</div>
2、使用react useRef()获取到input
const inputRef = useRef();
3.默认将input 进行隐藏(不隐藏会有input上传的原声样式,你也可以直接使用input原生修改样式,就省略了我的第一步和第二步)
<input
style={{ display: "none" }}
ref={inputRef}
className={styles.filess}
type="file"
accept="image/*"
mutiple="mutiple"
capture="camera"
onChange={(e) => handleUpload(e)}
/>
4.上传图片后获取到的值是文件流形式的参数,到这一步可以进行简单的拍照上传了,如果你发现拍照上传的图片比较大,时间比较长,用户体验上不是很好。可以继续往下看
const handleUpload = async (e) => {
console.log(e.nativeEvent.srcElement.files[0],"文件流形式");
};
5.拍照后图片过大的优化,
//压缩文件
function compressImg(file, quality) {
var qualitys = 0.52;
if (parseInt((file.size / 1024).toFixed(2)) < 1024) {
qualitys = 0.85;
}
if (5 * 1024 < parseInt((file.size / 1024).toFixed(2))) {
qualitys = 0.92;
}
if (quality) {
qualitys = quality;
}
if (file[0]) {
// 如果是 file 数组返回 Promise 数组
return Promise.all(Array.from(file).map((e) => compressImg(e, qualitys)));
} else {
return new Promise((resolve) => {
if ((file.size / 1024).toFixed(2) < 300) {
resolve({
file: file,
});
} else {
const reader = new FileReader(); // 创建 FileReader
reader.onload = ({ target: { result: src } }) => {
const image = new Image(); // 创建 img 元素
image.onload = async () => {
const canvas = document.createElement("canvas"); // 创建 canvas 元素
const context = canvas.getContext("2d");
var targetWidth = image.width;
var targetHeight = image.height;
var originWidth = image.width;
var originHeight = image.height;
if (
1 * 1024 <= parseInt((file.size / 1024).toFixed(2)) &&
parseInt((file.size / 1024).toFixed(2)) <= 10 * 1024
) {
var maxWidth = 1600;
var maxHeight = 1600;
targetWidth = originWidth;
targetHeight = originHeight;
// 图片尺寸超过的限制
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > maxWidth / maxHeight) {
// 更宽,按照宽度限定尺寸
targetWidth = maxWidth;
targetHeight = Math.round(
maxWidth * (originHeight / originWidth)
);
} else {
targetHeight = maxHeight;
targetWidth = Math.round(
maxHeight * (originWidth / originHeight)
);
}
}
}
if (
10 * 1024 <= parseInt((file.size / 1024).toFixed(2)) &&
parseInt((file.size / 1024).toFixed(2)) <= 20 * 1024
) {
maxWidth = 1400;
maxHeight = 1400;
targetWidth = originWidth;
targetHeight = originHeight;
// 图片尺寸超过的限制
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > maxWidth / maxHeight) {
// 更宽,按照宽度限定尺寸
targetWidth = maxWidth;
targetHeight = Math.round(
maxWidth * (originHeight / originWidth)
);
} else {
targetHeight = maxHeight;
targetWidth = Math.round(
maxHeight * (originWidth / originHeight)
);
}
}
}
canvas.width = targetWidth;
canvas.height = targetHeight;
context.clearRect(0, 0, targetWidth, targetHeight);
// 绘制 canvas
context.drawImage(image, 0, 0, targetWidth, targetHeight);
const。canvasURL = canvas.toDataURL("image/jpeg", qualitys);
const buffer = atob(canvasURL.split(",")[1]);
let length = buffer.length;
const bufferArray = new Uint8Array(new ArrayBuffer(length));
while (length--) {
bufferArray[length] = buffer.charCodeAt(length);
}
const miniFile = new File([bufferArray], file.name, {
type: "image/jpeg",
});
resolve({
file: miniFile,
origin: file,
beforeSrc: src,
afterSrc: canvasURL,
beforeKB: Number((file.size / 1024).toFixed(2)),
afterKB: Number((miniFile.size / 1024).toFixed(2)),
});
};
image.src = src;
};
reader.readAsDataURL(file);
}
});
}
}
6、upload上传就可以这么写
const handleUpload = async (e) => {
const base64Str = e.nativeEvent.srcElement.files[0];
compressImg(base64Str).then((res) => {
console.log(res.file, "res.file");
var formData = new FormData();
formData.append("file", res.file);
setUploadfileLoadding(true);
//将formData传递给后端就可以了
});
};
参考链接:前端图片最优压缩