1. 程式人生 > >JS獲取貼上板中的圖片進行展示和上傳

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中,應該也是通過剪下板獲取的,這裡卻獲取不到,沒有想出原因是什麼,不知道有沒有人知道原因。。