前言
成都創(chuàng)新互聯(lián)公司專注于網(wǎng)站建設(shè)|網(wǎng)站維護|優(yōu)化|托管以及網(wǎng)絡(luò)推廣,積累了大量的網(wǎng)站設(shè)計與制作經(jīng)驗,為許多企業(yè)提供了網(wǎng)站定制設(shè)計服務(wù),案例作品覆蓋陽臺護欄等行業(yè)。能根據(jù)企業(yè)所處的行業(yè)與銷售的產(chǎn)品,結(jié)合品牌形象的塑造,量身制作品質(zhì)網(wǎng)站。
我們在使用QQ進行聊天時,從別的地方Ctrl+C一張圖片,然后在聊天窗口Ctrl+V,QQ就會將你剛才復(fù)制的圖片粘貼到即將發(fā)送的消息容器里,按下Enter鍵,這張圖片將會發(fā)送出去。接下來跟各位開發(fā)者分享下這項功能在Vue中如何來實現(xiàn)。先跟大家展示下最終實現(xiàn)的效果。在線體驗地址
實現(xiàn)思路
實現(xiàn)過程
本片文章主要講解剪切板圖片的解析以及將base64圖片轉(zhuǎn)換成文件上傳至服務(wù)器,下方代碼中的axios的封裝以及websocket的配置與使用可參考我的另外兩篇文章:Vue合理配置axios并在項目中進行實際應(yīng)用和Vue合理配置WebSocket并實現(xiàn)群聊
監(jiān)聽剪切板事件(mounted生命周期中),將圖片渲染到即將發(fā)送到消息容器里
const that = this; document.body.addEventListener('paste', function (event) { // 自己寫的一個全屏加載插件,文章地址:https://juejin.im/post/5e3307145188252c30002fa7 that.$fullScreenLoading.show("讀取圖片中"); // 獲取當(dāng)前輸入框內(nèi)的文字 const oldText = that.$refs.msgInputContainer.textContent; // 讀取圖片 let items = event.clipboardData && event.clipboardData.items; let file = null; if (items && items.length) { // 檢索剪切板items for (let i = 0; i < items.length; i++) { if (items[i].type.indexOf('image') !== -1) { file = items[i].getAsFile(); break; } } } // 預(yù)覽圖片 const reader = new FileReader(); reader.onload = function(event) { // 圖片內(nèi)容 const imgContent = event.target.result; // 創(chuàng)建img標(biāo)簽 let img = document.createElement('img');//創(chuàng)建一個img // 獲取當(dāng)前base64圖片信息,計算當(dāng)前圖片寬高以及壓縮比例 let imgObj = new Image(); let imgWidth = ""; let imgHeight = ""; let scale = 1; imgObj.src = imgContent; imgObj.onload = function() { // 計算img寬高 if(this.width<400){ imgWidth = this.width; imgHeight = this.height; }else{ // 輸入框圖片顯示縮小10倍 imgWidth = this.width/10; imgHeight = this.height/10; // 圖片寬度大于1920,圖片壓縮5倍 if(this.width>1920){ // 真實比例縮小5倍 scale = 5; } } // 設(shè)置可編輯div中圖片寬高 img.width = imgWidth; img.height = imgHeight; // 壓縮圖片,渲染頁面 that.compressPic(imgContent,scale,function (newBlob,newBase) { // 刪除可編輯div中的圖片名稱 that.$refs.msgInputContainer.textContent = oldText; img.src = newBase; //設(shè)置鏈接 // 圖片渲染 that.$refs.msgInputContainer.append(img); that.$fullScreenLoading.hide(); }); }; }; reader.readAsDataURL(file); });
base64圖片壓縮函數(shù)
// 參數(shù): base64地址,壓縮比例,回調(diào)函數(shù)(返回壓縮后圖片的blob和base64) compressPic:function(base64, scale, callback){ const that = this; let _img = new Image(); _img.src = base64; _img.onload = function() { let _canvas = document.createElement("canvas"); let w = this.width / scale; let h = this.height / scale; _canvas.setAttribute("width", w); _canvas.setAttribute("height", h); _canvas.getContext("2d").drawImage(this, 0, 0, w, h); let base64 = _canvas.toDataURL("image/jpeg"); // 當(dāng)canvas對象的原型中沒有toBlob方法的時候,手動添加該方法 if (!HTMLCanvasElement.prototype.toBlob) { Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', { value: function (callback, type, quality) { let binStr = atob(this.toDataURL(type, quality).split(',')[1]), len = binStr.length, arr = new Uint8Array(len); for (let i = 0; i < len; i++) { arr[i] = binStr.charCodeAt(i); } callback(new Blob([arr], {type: type || 'image/png'})); } }); }else{ _canvas.toBlob(function(blob) { if(blob.size > 1024*1024){ that.compressPic(base64, scale, callback); }else{ callback(blob, base64); } }, "image/jpeg"); } } }
完善消息發(fā)送函數(shù),獲取輸入框里的所有子元素,找出base64圖片將其轉(zhuǎn)為文件并上傳至服務(wù)器(此處需要注意:base64轉(zhuǎn)文件時,需要用正則表達式刪掉base64圖片的前綴),將當(dāng)前圖片地址推送至websocket服務(wù)。
對下述代碼有不理解的地方,可閱讀我的另一篇文章:Vue實現(xiàn)圖片與文字混輸,
sendMessage: function (event) { if (event.keyCode === 13) { // 阻止編輯框默認(rèn)生成div事件 event.preventDefault(); let msgText = ""; // 獲取輸入框下的所有子元素 let allNodes = event.target.childNodes; for (let item of allNodes) { // 判斷當(dāng)前元素是否為img元素 if (item.nodeName === "IMG") { if (item.alt === "") { // 是圖片 let base64Img = item.src; // 刪除base64圖片的前綴 base64Img = base64Img.replace(/^data:image\/\w+;base64,/, ""); //隨機文件名 let fileName = (new Date()).getTime() + ".jpeg"; //將base64轉(zhuǎn)換成file let imgFile = this.convertBase64UrlToImgFile(base64Img, fileName, 'image/jpeg'); let formData = new FormData(); // 此處的file與后臺取值時的屬性一樣,append時需要添加文件名,否則一直時blob formData.append('file', imgFile, fileName); // 將圖片上傳至服務(wù)器 this.$api.fileManageAPI.baseFileUpload(formData).then((res) => { const msgImgName = `/${res.fileName}/`; // 消息發(fā)送: 發(fā)送圖片 this.$socket.sendObj({ msg: msgImgName, code: 0, username: this.$store.state.username, avatarSrc: this.$store.state.profilePicture, userID: this.$store.state.userID }); // 清空輸入框中的內(nèi)容 event.target.innerHTML = ""; }); } else { msgText += `/${item.alt}/`; } } else { // 獲取text節(jié)點的值 if (item.nodeValue !== null) { msgText += item.nodeValue; } } } // 消息發(fā)送: 發(fā)送文字,為空則不發(fā)送 if (msgText.trim().length > 0) { this.$socket.sendObj({ msg: msgText, code: 0, username: this.$store.state.username, avatarSrc: this.$store.state.profilePicture, userID: this.$store.state.userID }); // 清空輸入框中的內(nèi)容 event.target.innerHTML = ""; } } }
base64圖片轉(zhuǎn)flie
// base64轉(zhuǎn)file convertBase64UrlToImgFile: function (urlData, fileName, fileType) { // 轉(zhuǎn)換為byte let bytes = window.atob(urlData); // 處理異常,將ascii碼小于0的轉(zhuǎn)換為大于0 let ab = new ArrayBuffer(bytes.length); let ia = new Int8Array(ab); for (let i = 0; i < bytes.length; i++) { ia[i] = bytes.charCodeAt(i); } // 轉(zhuǎn)換成文件,添加文件的type,name,lastModifiedDate屬性 let blob = new Blob([ab], {type: fileType}); blob.lastModifiedDate = new Date(); blob.name = fileName; return blob; } axios文件上傳接口的封裝(注意:需要設(shè)置"Content-Type":"multipart/form-data"}) /* * 文件管理接口 * */ import services from '../plugins/axios' import base from './base'; // 導(dǎo)入接口域名列表 const fileManageAPI = { // 單文件上傳 baseFileUpload(file){ return services._axios.post(`${base.lkBaseURL}/uploads/singleFileUpload`,file,{headers:{"Content-Type":"multipart/form-data"}}); } }; export default fileManageAPI;
解析websocket推送的消息
// 消息解析 messageParsing: function (msgObj) { // 解析接口返回的數(shù)據(jù)并進行渲染 let separateReg = /(\/[^/]+\/)/g; let msgText = msgObj.msgText; let finalMsgText = ""; // 將符合條件的字符串放到數(shù)組里 const resultArray = msgText.match(separateReg); if (resultArray !== null) { for (let item of resultArray) { // 刪除字符串中的/符號 item = item.replace(/\//g, ""); // 判斷是否為圖片: 后綴為.jpeg if(this.isImg(item)){ // 解析為img標(biāo)簽 const imgTag = `<img src="${base.lkBaseURL}/upload/image/${item}" alt="聊天圖片">`; // 替換匹配的字符串為img標(biāo)簽:全局替換 msgText = msgText.replace(new RegExp(`/${item}/`, 'g'), imgTag); } } finalMsgText = msgText; } else { finalMsgText = msgText; } msgObj.msgText = finalMsgText; // 渲染頁面 this.senderMessageList.push(msgObj); // 修改滾動條位置 this.$nextTick(function () { this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight; }); }
判斷當(dāng)前字符串是否為有圖片后綴
// 判斷是否為圖片 isImg: function (str) { let objReg = new RegExp("[.]+(jpg|jpeg|swf|gif)$", "gi"); return objReg.test(str); }
踩坑記錄
直接將base64格式的圖片通過websocket發(fā)送至服務(wù)端
結(jié)果很明顯,服務(wù)端websocket服務(wù)報錯,報錯原因:內(nèi)容超過最大長度。
前端通過post請求將base64碼傳到服務(wù)端,服務(wù)端直接將base64碼解析為圖片保存至服務(wù)器
從下午2點折騰到晚上6點,一直在找Java解析base64圖片存到服務(wù)器的方案,最終選擇了放棄,采用了前端轉(zhuǎn)換方式,這里的問題大概是前端傳base64碼到后端時,http請求會進行轉(zhuǎn)義,導(dǎo)致后端解析得到的base64碼是錯誤的,所以一直沒有成功。
項目地址:chat-system
總結(jié)
以上所述是小編給大家介紹的Vue解析剪切板圖片并實現(xiàn)發(fā)送功能,希望對大家有所幫助!
標(biāo)題名稱:Vue解析剪切板圖片并實現(xiàn)發(fā)送功能
鏈接URL:http://www.rwnh.cn/article48/gdihep.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、軟件開發(fā)、品牌網(wǎng)站建設(shè)、外貿(mào)建站、網(wǎng)站設(shè)計公司、靜態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)