爬坑日记(截图上传)
后台管理系统实现截图上传功能
最近在工作中遇到一个需求,要求上传图片时,支持第三方截图功能,也就是我们常说的( QQ,微信截图)
分析流程
- 如何获取剪贴板的内容 ;
- 是否有对应的组件使用
- 怎样获得阿里云的签名;
- 获得阿里云签名以后再次上传;
- 组件传值;
如何获取剪贴板的内容
再百度,以及观看antd组件的源码,以及观看项目以前的图片上传以后,发现可以使用onPaste获得剪贴板的内容
这次主要使用原生加react-hook
// 在return中准备一个textarea
<textarea id="text" onPaste={handelePaste} className={styles.CopyInput}></textarea>;
//className只是用来控制输入框的大小
//获得图片以后还需要准备一个img用来显示图片
<img src={ImgUrlShow} id="imgNode" style={{width:'180px',height:'180px'}}/>
//此处的src定义了一个可变的地址链接,这个后面会说到,别着急
接下来咱们看handelePaste函数中的代码
function handelePaste (event) {
var isChrome = false;
if (event.clipboardData || event.originalEvent) {
//某些chrome版本使用的是event.originalEvent
var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
if(clipboardData.items){
// for chrome
var items = clipboardData.items,
len = items.length,
blob = null;
isChrome = true;
for (var i = 0; i < len; i++) {
if (items[i].type.indexOf("image") !== -1) {
//getAsFile() 此方法只是living standard firefox ie11 并不支持
blob = items[i].getAsFile();
}
}
}
}
}
//上面的代码片段就是获取剪贴板的核心代码块了,blob就是你拿到的文件了,可以打印看一下
是否有合适的组件使用
想啥呢小老弟,肯定是没有(如果你发现了,请偷偷告诉我)
获得阿里云的签名
下面就来展示获得阿里云签名的方法,敲黑板了,下面我用到的是后端直接给的接口,然后封装后方法,所以同学们,不要牛角尖哦
//前面我们已经拿到
function handelePaste (event) {
var isChrome = false;
if (event.clipboardData || event.originalEvent) {
//某些chrome版本使用的是event.originalEvent
var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
if(clipboardData.items){
// for chrome
var items = clipboardData.items,
len = items.length,
blob = null;
isChrome = true;
for (var i = 0; i < len; i++) {
if (items[i].type.indexOf("image") !== -1) {
//getAsFile() 此方法只是living standard firefox ie11 并不支持
blob = items[i].getAsFile();
}
}
//注意我要加代码了
if((blob!==null){
//下面这句,不懂就打印一下,就是截取字符串
const _file = blob.name.split('.');
//这里我们整合一下获取签名所需要的传参(参数根据你们的接口来,切忌直接搬运)
let params = {
dir: '项目名称', //这个地方需要写入你的项目名称
fileName: `nrfile${Date.now()}${Math.ceil(Math.random() * 10000)}`,
suffix: _file[1]
}
//这里就是封装的请求方法了,切记不要牛角尖
filaAutograph(params).then(res => {
console.log(res,78798797)
//这里是我为了下一个接口准备的参数(根据各自的接口来,切忌直接搬运)
let OSSData ={
key:res.data.host + res.data.dir,
OSSAccessKeyId: res.data.accessid,
policy: res.data.policy,
Signature: res.data.signature,
success_action_status: "200",
file:blob //这个file传过去就是file: (binary)
}
}
}
}
}
再次上传阿里云
再这里问题就来了,我再这里遇到一个请求头的问题
就是fromData没有数据
下面是以解决的代码了
//前面我们已经拿到
function handelePaste (event) {
var isChrome = false;
if (event.clipboardData || event.originalEvent) {
//某些chrome版本使用的是event.originalEvent
var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
if(clipboardData.items){
// for chrome
var items = clipboardData.items,
len = items.length,
blob = null;
isChrome = true;
for (var i = 0; i < len; i++) {
if (items[i].type.indexOf("image") !== -1) {
//getAsFile() 此方法只是living standard firefox ie11 并不支持
blob = items[i].getAsFile();
}
}
//注意我要加代码了
if((blob!==null){
//下面这句,不懂就打印一下,就是截取字符串
const _file = blob.name.split('.');
//这里我们整合一下获取签名所需要的传参(参数根据你们的接口来,切忌直接搬运)
let params = {
dir: 'ade-admin-html',
fileName: `nrfile${Date.now()}${Math.ceil(Math.random() * 10000)}`,
suffix: _file[1]
}
//这里就是封装的请求方法了,切记不要牛角尖
filaAutograph(params).then(res => {
console.log(res,78798797)
//这里是我为了下一个接口准备的参数(根据各自的接口来,切忌直接搬运)
let OSSData ={
key:res.data.host + res.data.dir,
OSSAccessKeyId: res.data.accessid,
policy: res.data.policy,
Signature: res.data.signature,
success_action_status: "200",
file:blob //这个file传过去就是file: (binary)
}
})
//敲黑板,我又要加代码了(参数根据各自的接口来,切忌直接搬运)
const filename = Date.now() + ''+Math.ceil(Math.random() * 10000) + suffix;
//let imgUrlg = OSSData.host + '/' + OSSData.key +'/' + filename;
//用到上面准备的参数了,注意看哈
let Queryparams = {
name: filename,
OSSAccessKeyId: OSSData.OSSAccessKeyId,
policy: OSSData.policy,
signature: OSSData.Signature,
// expire: OSSData.expire,
key: OSSData.key
success_action_status: '200',
file: blob
};
//这里我们用便利的方法,把它全部加到formData 里面去
const formData = new FormData()
//new这是一个实例对象
Object.keys(Queryparams).forEach(key => {
formData.append(key,Queryparams[key])
})
//说一下,这里我们为什么用axios直接请求,不经过拦截器了,原因很简单,我们项目里的拦截器不支持我请求这个接口
Axios({
method:'post',
url:'https://image.newrank.cn/',//这里根据你们后端提供的接口来
data:formData,
headers:{
'Content-Type': 'multipart/form-data'
}
}).then(res => {
console.log(res,22222)
})
}
}
}
基本上到这里就全剧终了
但是!!!
有的同学肯定会说,我不需要你这些参数,我上传base64就好了。放心,这一点也给你安排上
//前面我们已经拿到
function handelePaste (event) {
var isChrome = false;
if (event.clipboardData || event.originalEvent) {
//某些chrome版本使用的是event.originalEvent
var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
if(clipboardData.items){
// for chrome
var items = clipboardData.items,
len = items.length,
blob = null;
isChrome = true;
for (var i = 0; i < len; i++) {
if (items[i].type.indexOf("image") !== -1) {
//getAsFile() 此方法只是living standard firefox ie11 并不支持
blob = items[i].getAsFile();
}
}
//注意我要加代码了
if((blob!==null){
//这里是全新版本
//下面这一句是直接给了你一个blob对象显示图片的地址
var blobUrl=URL.createObjectURL(blob);
setImgUrl(blobUrl)
var reader = new FileReader();
// //base64码显示
reader.onload = function (event) {
// event.target.result 即为图片的Base64编码字符串
// console.log(event.target.result,'******')
//可以在这里写请求
}
reader.readAsDataURL(blob);
}
}
}
跨域问题
当然也用同学们会遇到跨域的问题,因为咱们这个毕竟没有用antd的组件
所以这个时候怎么办呢???
别担心,坑我都帮你们爬过了!!!
1.代理跨域,没用
2.公司阿里云允许所有请求方式,这也没用
3.肯定有人会说,哈哈,白天写BUG了吧
害,谁让我菜呢
看到这里的孩子们,一定焦头烂额了,所以来吧看代码
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片
.
// An highlighted block
import React from "react";
import {Input} from "antd";
// import { getUploadImage } from '@/services/adUserManage';
import styles from './index.less'
import Axios from "axios";
const ImageCopy = (props ={}) => {
console.log(props)
//这里是从父组件拿到的一些状态逻辑,和图片地址,还要函数
//主要是用来点击切换什么的
//这里的初始值 handleAgain === true ---- ImgUrlShow === undefined ,changeshowImg函数
let { handleAgain,changeshowImg,ImgUrlShow } = props
console.log(456789,imgUrl)
function handelePaste (event) {
var isChrome = false;
if (event.clipboardData || event.originalEvent) {
//某些chrome版本使用的是event.originalEvent
var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
if(clipboardData.items){
// for chrome
var items = clipboardData.items,
len = items.length,
blob = null;
isChrome = true;
for (var i = 0; i < len; i++) {
if (items[i].type.indexOf("image") !== -1) {
//getAsFile() 此方法只是living standard firefox ie11 并不支持
blob = items[i].getAsFile();
}
}
if(blob!==null){
const url = '接口地址' //这里建议配置一个测试,生产这样的一个请求环境
const formData = new FormData()
formData.append("file", blob);
Axios({
method:'post',
url:url,
data:formData,
headers:{
'Content-Type': 'multipart/form-data'
}
}).then(res => {
//子组件调用了父组件的方法,然后在给父组件传值
//传的是图片地址
changeshowImg(res.data.value.data)
})
}
}
}
}
return (
<div className={styles.CopyUploadComponent}>
//不要纠结这里的几个判断,如果你没有点击切换的功能,可以删去,如果你需要,也要仔细看过之后,再使用
{
ImgUrlShow !== undefined && handleAgain !== false ? <img src={ImgUrlShow} id="imgNode" style={{width:'180px',height:'180px'}}/>
:<textarea id="text" onPaste={handelePaste} className={styles.CopyInput}></textarea>
}
</div>
)
}
export default ImageCopy
上面这部分是后端重写了一个接口,只需要上传file: (binary),
因为咱们第一步直接拿的就是文件,所以不需要转化,直接传
上面这些问题就是我在工作中遇到的,可能不太适合你们,但是基本上是这个思路,其实还有很多细致的地方,这里没说到,等我下次有时间再来更新吧
还有一个问题
要是跨域解决不了,就直接找后端给你新接口
不足的地方,请各位大佬指出