本篇主要介绍了通过获取剪贴板中的图片内容,上传文件内容到七牛中,然后使用返回的图片地址来实现在线聊天的图片发送。要完整地运行其中的例子,需要项目具备的接收和发送消息的逻辑。主要内容结构如下
- 需求分析:简单介绍需求和要实现的效果
- 过程分析:根据已经实现的结果,概括下实现步骤
- 实现过程:逐步实现一个读取图片上传和获取文件地址的过程
需求分析
在项目的在线聊天功能中,已经具备了发送文字和图片的功能,为了方便用户使用,要求在用户截取图片/复制图片以后,直接在聊天的输入框中粘贴,点击确定即可直接发送图片。微信的网页版在线聊天中有类似的效果如下:
image.png在很多站点中,也有类似的应用,比如在线编辑文档/帖子的回复输入框中,想要通过这种方式插入图片都会用到这样的实现。
过程分析
为了做到简明,用伪码来表述这个过程:
document.paste => (pastEvent) {
file = getLastOneFilePasted(pastEvent);
reader = createFileReader();
reader.onload => (loadEvent) {
content = getLoadContent(loadEvent)
uploadContentToQiniu( (response) => { // callback
url = formatImageUrl(response)
sendImg(img)
})
}
reader.read(file);
}
- 可以通过document的事件监听到,用户在输入框中进行了粘贴。
- 通过事件可以获取到粘贴的文件对象。
- 创建一个FileReader并读取文件对象,即可在onload的的handler中进行对应处理。
- onload中提供了事件对象可以获取到加载的文件内容。
- 执行上传操作,将文件内容上传到七牛上,七牛返回上传成功后的文件信息。
- 基于将七牛返回的文件信息,组织发送图片的业务逻辑代码。
实现过程
获取文件内容
为了方便引入了jquery,如下代码能够实现在控制台打印获粘贴的文件内容。注:这里获取的粘贴的文件列表是一个数组,为了简化处理,我们只把粘贴的最后一张图片进行发送。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="jquery.js"></script>
<style>
textarea {
width: 400px;
height: 160px;
}
</style>
</head>
<body>
<textarea class="chat-textarea"></textarea>
<script>
document.onpaste = function (event) {
if($(event.target).hasClass('chat-textarea')){
let items = (event.clipboardData || event.originalEvent.clipboardData).items;
let item = items[items.length - 1];
if (item.kind === 'file' && item.type == "image/png") {
var blob = item.getAsFile();
var reader = new FileReader();
reader.onload = function (event) {
console.log(event.target.result);
};
reader.readAsDataURL(blob);
}
}
};
</script>
</body>
</html>
其中onpaste获取的event对象如下,我们可以通过items都可以获取到粘贴的图片的内容,这里items有两个内容,一个是张贴的图片名字,另一个是截图生成的png。我们需要只对png类型的图片做处理。
如下为控制台打印的数出内容:
可以看到输出内容格式形如如下格式的内容:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAsgAAAKyCAYAAADIEijRAAAgAElEQVR4AeydBZhkxfX2T+vIugssurgnhBAggUCIQIy4EuMj7gnEXYj7P24QIUYUCSEEghNcFltgYWHdZ0fav+dXPdVz587tnu7Rnpn3PM9Md99bt+Ste0+9derUubHOjm2lwuarrbTpcosXuyzZOsPiyZR5KRULls90WiFfsticI23GPq/3p/QpBISAEBACQkAICAEhIAQmHQJxWpSYd5zF2ve2YrFkhXzGSqVipaGxeMLiyVazUs5KHfdVjuuLEBAC
这种格式成为data URI scheme(wiki),它作为内容格式提供了在网页中直接内容的能力,这样就不需要多个HTTP请求单独的文件了。其中前面是属于定式,其中base64表示data部分是二进制文件,使用ASCII格式处理并采用了Base64进行binary-to-text的转化。
将文件上传到七牛并获得文件地址
要获得七牛的存储空间,首先要注册一个七牛开发者账号,并拿到AccessKey/SecretKey用于生成token。另外为了上传,你还需要创建自己的存储空间。
七牛的上传分为客户端上传和服务器端上传,我们采用个但是客户端上传。首先在客户端也就是网页端引入qiniu.js,最简单的方式是引用remote js,这里我们引入最新版本的2.2.2版:
<script src="https://unpkg.com/qiniu-js@2.2.2/dist/qiniu.min.js"></script>
其次是客户端的token生成。为了保证安全性,我们要先获取一个由后台生成的上传token,它通常是由后台api实时提供。我们直接使用七牛提供的node.js示例用于执行得到token。
首先初始化一个项目,然后安装qiniu:
$ npm init -y
$ npm install --save qiniu
然后新建一个文件token.js
:
//token.js
var qiniu = require("qiniu");
var accessKey = 'Your accessKey';
var secretKey = 'Your secretKey';
var mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
var options = {
scope: "Your Scope",
};
var putPolicy = new qiniu.rs.PutPolicy(options);
var uploadToken=putPolicy.uploadToken(mac);
console.log(uploadToken)
通过执行 node token.js
得到可用的上传token(这里只是为了方便演示,在实际开发中需要由后台提供实时的token)。
参考官方的例子书写我们的上传图片的JavaScript代码:
// 此处是华东空间的上传路径,自己创建空间如果非华东可能会有些不同
let putUrl = "http://up.qiniu.com/putb64/-1";
// download domain可以在自己创建的上传空间中看到
let downloadDomain = "Your download domain";
// 通过token.js代码生成的值
let uploadToken = "Your upload token";
function putb64(pic, token, callback){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange=function(){
if (xhr.readyState==4){
var response = JSON.parse(xhr.responseText)
callback(downloadDomain + response.key)
}
}
xhr.open("POST", putUrl, true);
xhr.setRequestHeader("Content-Type", "application/octet-stream");
xhr.setRequestHeader("Authorization", `UpToken ${token}`);
xhr.send(pic);
}
关于header设置的Content-Type可以参考这篇进行了解。
在前例中我们已经得到了图片对内容,只需要裁切掉前置部分,提取图片内容用于调用put64即可:
var content = event.target.result;
// 去除非内容部分
// 注:不同media type的的data URI需要裁切的字符数可能会不同
var pic = content.substr(22);
putb64(pic, token, (url) => {
// use the url for custom use
});
得到图片的url以后,就可以结合业务代码进行IM相关的发送逻辑了。
最后给出一个完整的示例如下:
//token.js
var qiniu = require("qiniu");
var accessKey = 'Your accessKey';
var secretKey = 'Your secretKey';
var mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
var options = {
scope: "Your Scope",
};
var putPolicy = new qiniu.rs.PutPolicy(options);
var uploadToken=putPolicy.uploadToken(mac);
console.log(uploadToken)
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="jquery.js"></script>
<script src="https://unpkg.com/qiniu-js@2.2.2/dist/qiniu.min.js"></script>
<style>
textarea {
width: 400px;
height: 160px;
}
</style>
</head>
<body>
<textarea class="chat-textarea"></textarea>
<script>
let putUrl = "http://up.qiniu.com/putb64/-1"; //仅适用于华东的存储空间
let downloadDomain = 'Your download domain';
let uploadToken = "Your upload token";
function putb64(pic, token, callback){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange=function(){
if (xhr.readyState==4){
var response = JSON.parse(xhr.responseText)
callback(downloadDomain + response.key)
}
}
xhr.open("POST", putUrl, true);
xhr.setRequestHeader("Content-Type", "application/octet-stream");
xhr.setRequestHeader("Authorization", `UpToken ${token}`);
xhr.send(pic);
}
document.onpaste = function (event) {
if($(event.target).hasClass('chat-textarea')){
let items = (event.clipboardData || event.originalEvent.clipboardData).items;
let item = items[items.length - 1];
if (item.kind === 'file' && item.type == "image/png") {
var blob = item.getAsFile();
var reader = new FileReader();
reader.onload = function (event) {
var token = uploadToken;
var content = event.target.result;
var pic = content.substr(22);
putb64(pic, token, (url) => {
var img = document.createElement(`img`);
img.setAttribute('src', url);
document.body.append(img)
});
};
reader.readAsDataURL(blob);
}
}
};
</script>
</body>
</html>
网友评论