每一份堅持都是成功的累積,只要相信本身,總會遇到驚喜😜javascript
咱們在使用QQ進行聊天時,從別的地方Ctrl+C一張圖片,而後在聊天窗口Ctrl+V,QQ就會將你剛纔複製的圖片粘貼到即將發送的消息容器裏,按下Enter鍵,這張圖片將會發送出去。接下來跟各位開發者分享下這項功能在Vue中如何來實現。先跟你們展現下最終實現的效果。在線體驗地址 html
本片文章主要講解剪切板圖片的解析以及將base64圖片轉換成文件上傳至服務器,下方代碼中的axios的封裝以及websocket的配置與使用可參考個人另外兩篇文章:Vue合理配置axios並在項目中進行實際應用和Vue合理配置WebSocket並實現羣聊前端
監聽剪切板事件(mounted生命週期中),將圖片渲染到即將發送到消息容器裏java
/** * 監聽粘貼監聽事件: 實現圖片粘貼 */
let that = this;
document.body.addEventListener('paste', function (e) {
// 監聽文件流
let reader = new FileReader();
let clipboard = e.clipboardData;
reader.onload = function (evt) {
// 建立一個img
let img = document.createElement('img');
img.src = evt.target.result;//設置連接
// 圖片渲染
that.$refs.msgInputContainer.append(img);
};
let file = clipboard.items[0];
if (file.kind == 'file') {
reader.readAsDataURL(file.getAsFile());//啓動文件流事件
}
});
複製代碼
完善消息發送函數,獲取輸入框裏的全部子元素,找出base64圖片將其轉爲文件並上傳至服務器(此處須要注意:base64轉文件時,須要用正則表達式刪掉base64圖片的前綴),將當前圖片地址推送至websocket服務。node
對下述代碼有不理解的地方,可閱讀個人另外一篇文章:Vue實現圖片與文字混輸,ios
sendMessage: function (event) {
if (event.keyCode === 13) {
// 阻止編輯框默認生成div事件
event.preventDefault();
let msgText = "";
// 獲取輸入框下的全部子元素
let allNodes = event.target.childNodes;
for (let item of allNodes) {
// 判斷當前元素是否爲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轉換成file
let imgFile = this.convertBase64UrlToImgFile(base64Img, fileName, 'image/jpeg');
let formData = new FormData();
// 此處的file與後臺取值時的屬性同樣,append時須要添加文件名,不然一直時blob
formData.append('file', imgFile, fileName);
// 將圖片上傳至服務器
this.$api.fileManageAPI.baseFileUpload(formData).then((res) => {
const msgImgName = `/${res.fileName}/`;
// 消息發送: 發送圖片
this.$socket.sendObj({
msg: msgImgName,
code: 0,
username: this.$store.state.username,
avatarSrc: this.$store.state.profilePicture,
userID: this.$store.state.userID
});
// 清空輸入框中的內容
event.target.innerHTML = "";
});
} else {
msgText += `/${item.alt}/`;
}
} else {
// 獲取text節點的值
if (item.nodeValue !== null) {
msgText += item.nodeValue;
}
}
}
// 消息發送: 發送文字,爲空則不發送
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
});
// 清空輸入框中的內容
event.target.innerHTML = "";
}
}
}
複製代碼
base64圖片轉flieweb
// base64轉file
convertBase64UrlToImgFile: function (urlData, fileName, fileType) {
// 轉換爲byte
let bytes = window.atob(urlData);
// 處理異常,將ascii碼小於0的轉換爲大於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);
}
// 轉換成文件,添加文件的type,name,lastModifiedDate屬性
let blob = new Blob([ab], {type: fileType});
blob.lastModifiedDate = new Date();
blob.name = fileName;
return blob;
}
複製代碼
axios文件上傳接口的封裝(注意:須要設置"Content-Type":"multipart/form-data"})正則表達式
/* * 文件管理接口 * */
import services from '../plugins/axios'
import base from './base'; // 導入接口域名列表
const fileManageAPI = {
// 單文件上傳
baseFileUpload(file){
return services._axios.post(`${base.lkBaseURL}/uploads/singleFileUpload`,file,{headers:{"Content-Type":"multipart/form-data"}});
}
};
export default fileManageAPI;
複製代碼
解析websocket推送的消息axios
// 消息解析
messageParsing: function (msgObj) {
// 解析接口返回的數據並進行渲染
let separateReg = /(\/[^/]+\/)/g;
let msgText = msgObj.msgText;
let finalMsgText = "";
// 將符合條件的字符串放到數組裏
const resultArray = msgText.match(separateReg);
if (resultArray !== null) {
for (let item of resultArray) {
// 刪除字符串中的/符號
item = item.replace(/\//g, "");
// 判斷是否爲圖片: 後綴爲.jpeg
if(this.isImg(item)){
// 解析爲img標籤
const imgTag = `<img src="${base.lkBaseURL}/upload/image/${item}" alt="聊天圖片">`;
// 替換匹配的字符串爲img標籤:全局替換
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;
});
}
複製代碼
判斷當前字符串是否爲有圖片後綴後端
// 判斷是否爲圖片
isImg: function (str) {
let objReg = new RegExp("[.]+(jpg|jpeg|swf|gif)$", "gi");
return objReg.test(str);
}
複製代碼
結果很明顯,服務端websocket服務報錯,報錯緣由:內容超過最大長度。
從下午2點折騰到晚上6點,一直在找Java解析base64圖片存到服務器的方案,最終選擇了放棄,採用了前端轉換方式,這裏的問題大概是前端傳base64碼到後端時,http請求會進行轉義,致使後端解析獲得的base64碼是錯誤的,因此一直沒有成功。