JS獲取貼上板中的圖片進行展示和上傳
目前有一個需求,需要在頁面中獲取QQ、微信等軟體的截圖上傳到伺服器,為了使用者體驗,不能讓使用者主動上傳,提供給使用者方法,在web頁面使用貼上快捷鍵,就可以貼上到頁面,然後點擊發送進行上傳。而且使用者如果貼上的是文字也需要能正常傳送文字內容。
這個需求需要分為四個部分:
1、構造頁面,存放獲取的資料
2、獲取貼上板中的內容
3、在頁面展示獲取的內容
4、將獲取的圖片內容傳送到伺服器儲存
首先看第一部分,構造頁面,這裡省去其他部分,主要介紹這個功能,因此只需要在body標籤中存在兩個div,一個儲存展示的圖片,一個用於輸入文字。在預設情況下可以輸入文字,因此這時展示圖片的div是隱藏狀態,具體程式碼如下:
<body> <div id="jietuWrap" class="b1" style="display:none;"> <img id="jietuImg" src=""> <br /> <button class="sendBtn" onclick="send_msg()">傳送</button> </div> <div class="b1"> <textarea id="dope" class="newtextarea" style="width: 99%; border: none; outline: none; resize: none; font-size: 15px; color: black;" onkeydown="suball()"></textarea> <br /> <button class="sendBtn" onclick="send_msg()">傳送</button> </div> </body>
然後是第二、三部分,獲取貼上板的內容並展示,可以通過window物件的子物件clipboardData物件獲取,其中儲存了複製、剪下、貼上的內容,這裡只需要用到貼上部分。ClipboardEvent物件中就包含了clipboardData物件,我們在監聽到貼上事件時,就可以獲取到ClipboardEvent,然後獲取到clipboardData物件,它是一個DataTransfer型別的物件,DataTransfer是拖動產生的一個物件,但實際上貼上事件也是它:
從其中可以看到,data就是獲取到的clipboardData物件物件,具體內容如下:
dropEffect: "none" effectAllowed: "uninitialized" files: FileList {length: 0} items: DataTransferItemList 0: DataTransferItem kind: "file" type: "image/png" __proto__: DataTransferItem getAsFile: ƒ getAsFile() getAsString: ƒ getAsString() kind: (...) type: (...) webkitGetAsEntry: ƒ webkitGetAsEntry() constructor: ƒ DataTransferItem() Symbol(Symbol.toStringTag): "DataTransferItem" get kind: ƒ () get type: ƒ () __proto__: Object length: 1 __proto__: DataTransferItemList types: ["Files"] __proto__: DataTransfer
這是獲取貼上板的內容,所以最主要用到的是items物件,items是一個DataTransferItemList物件,裡面是DataTransferItem型別的資料。items的DataTransferItem有兩個屬性kind和type:
kind |
String或者file |
type |
具體的資料型別,比如字串型別或者是檔案的型別,即MIME-TYPE |
比如這裡的例子中kind就是file,type是image/png。
還要用到一個方法來獲取具體的檔案或字串的內容,即示例中的getAsFile()和getAsString()方法,從名字就可以看出來獲取圖片等檔案就用getAsFile(),獲取字串就用getAsString()。
上面的例子就可以通過var blob=data.items[0].getAsFile();來獲取圖片內容。然後獲取圖片的base64流,通過ajax就可以上傳到伺服器。
下面列出第一部分,獲取剪下板中的內容的程式碼:
//繫結貼上事件 Ctrl+V
bindPaste();
//繫結貼上事件
function bindPaste(){
//定義變數儲存獲取的圖片內容
var blob;
//獲取body物件
var body = document.getElementsByTagName("body");
//定義body標籤繫結的貼上事件處理函式
var fun=function(e){
//獲取clipboardData物件
var data=e.clipboardData||window.clipboardData;
//獲取圖片內容
blob=data.items[0].getAsFile();
//判斷是不是圖片,最好通過檔案型別判斷
var isImg=(blob&&1)||-1;
var reader=new FileReader();
if(isImg>=0){
//將檔案讀取為 DataURL
reader.readAsDataURL(blob);
}
//檔案讀取完成時觸發
reader.onload=function(event){
//獲取base64流
var base64_str=event.target.result;
//div中的img標籤src屬性賦值,可以直接展示圖片
$("#jietuImg").attr("src",base64_str);
//顯示div
$("#jietuWrap").css("display","block");
//隱藏輸入文字的div
$("#jietuWrap").next().css("display","none");
}
}
//通過body標籤繫結貼上事件,注意有些標籤繫結貼上事件可能出錯
body[0].removeEventListener('paste',fun);
body[0].addEventListener('paste',fun);
}
最後就是將獲取的圖片的base64流通過ajax傳送到伺服器儲存到資源伺服器了,前端ajax大致如下:
// 上傳的資料除了圖片外,還可以包含自己需要傳遞的引數
var data = {
userId : $('#userId').val(),
base64 : savedPictureContent
};
$.ajax({
type : "POST",
url : "${ctx}/../jsp/fileInfo/sendPrintScreen.action",
dataType : "json",
data : data,
success : function(data) {
var res = data.result;
if (!res) {
alert("上傳失敗!");
} else {
alert("上傳成功!");
}
},
error : function() {
alert("由於網路原因,上傳失敗。");
}
});
後端處理程式碼:
/**
* base64圖片上傳(截圖)
*/
@RequestMapping("/sendPrintScreen")
public void sendPrintScreen(String userId,String base64){
if (StringUtils.isNotEmpty(base64))
{
if (base64.contains("base64,"))
{
base64=base64.substring(base64.indexOf("base64,")+7);
}
}
MultipartFile sendFile=BASE64DecodedMultipartFile.base64ToMultipartFile(base64);
//上傳檔案的工具類
this.sendFileUtil(sendFile userId);
}
注意後臺獲取base64流時必須要從字串"base64, "後面開始擷取,否則儲存的圖片會有問題。
最新測試發現,只可以獲取到複製的QQ、微信、檔案內的圖片,如果是資料夾內儲存的圖片檔案,複製之後是獲取不到的。但是既然這種檔案可以複製到比如Word中,應該也是通過剪下板獲取的,這裡卻獲取不到,沒有想出原因是什麼,不知道有沒有人知道原因。。