欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue解析剪切板圖片并實(shí)現(xiàn)發(fā)送功能

 更新時(shí)間:2020年02月04日 14:36:02   作者:神奇的程序員  
這篇文章主要介紹了Vue解析剪切板圖片并實(shí)現(xiàn)發(fā)送功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

前言

我們?cè)谑褂肣Q進(jìn)行聊天時(shí),從別的地方Ctrl+C一張圖片,然后在聊天窗口Ctrl+V,QQ就會(huì)將你剛才復(fù)制的圖片粘貼到即將發(fā)送的消息容器里,按下Enter鍵,這張圖片將會(huì)發(fā)送出去。接下來跟各位開發(fā)者分享下這項(xiàng)功能在Vue中如何來實(shí)現(xiàn)。先跟大家展示下最終實(shí)現(xiàn)的效果。在線體驗(yàn)地址

實(shí)現(xiàn)思路

  • 頁面掛載時(shí)監(jiān)聽剪切板粘貼事件
  • 監(jiān)聽文件流
  • 讀取文件流中的數(shù)據(jù)
  • 創(chuàng)建img標(biāo)簽
  • 將獲取到的base64碼賦值到img標(biāo)簽的src屬性
  • 將生成的img標(biāo)簽append到即將發(fā)送的消息容器里
  • 監(jiān)聽回車事件
  • 獲取可編輯div容器中的所有子元素
  • 遍歷獲取到的元素,找出img元素
  • 判斷當(dāng)前img元素是否有alt屬性(表情插入時(shí)有alt屬性),
  • 如果沒有alt屬性當(dāng)前元素就是圖片
  • 將base64格式的圖片轉(zhuǎn)成文件上傳至服務(wù)器
  • 上傳成功后,將服務(wù)器返回的圖片地址推送到websocket服務(wù)
  • 客戶端收到推送后,渲染頁面

實(shí)現(xiàn)過程

本片文章主要講解剪切板圖片的解析以及將base64圖片轉(zhuǎn)換成文件上傳至服務(wù)器,下方代碼中的axios的封裝以及websocket的配置與使用可參考我的另外兩篇文章:Vue合理配置axios并在項(xiàng)目中進(jìn)行實(shí)際應(yīng)用Vue合理配置WebSocket并實(shí)現(xiàn)群聊

監(jiān)聽剪切板事件(mounted生命周期中),將圖片渲染到即將發(fā)送到消息容器里

const that = this;
document.body.addEventListener('paste', function (event) {
 // 自己寫的一個(gè)全屏加載插件,文章地址: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)建一個(gè)img
 // 獲取當(dāng)前base64圖片信息,計(jì)算當(dāng)前圖片寬高以及壓縮比例
 let imgObj = new Image();
 let imgWidth = "";
 let imgHeight = "";
 let scale = 1;
 imgObj.src = imgContent;
 imgObj.onload = function() {
  // 計(jì)算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){
   // 真實(shí)比例縮小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對(duì)象的原型中沒有toBlob方法的時(shí)候,手動(dòng)添加該方法
  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)文件時(shí),需要用正則表達(dá)式刪掉base64圖片的前綴),將當(dāng)前圖片地址推送至websocket服務(wù)。

對(duì)下述代碼有不理解的地方,可閱讀我的另一篇文章:Vue實(shí)現(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,/, "");
   //隨機(jī)文件名
   let fileName = (new Date()).getTime() + ".jpeg";
   //將base64轉(zhuǎn)換成file
   let imgFile = this.convertBase64UrlToImgFile(base64Img, fileName, 'image/jpeg');
   let formData = new FormData();
   // 此處的file與后臺(tái)取值時(shí)的屬性一樣,append時(shí)需要添加文件名,否則一直時(shí)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é)點(diǎn)的值
  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ù)并進(jìn)行渲染
 let separateReg = /(\/[^/]+\/)/g;
 let msgText = msgObj.msgText;
 let finalMsgText = "";
 // 將符合條件的字符串放到數(shù)組里
 const resultArray = msgText.match(separateReg);
 if (resultArray !== null) {
  for (let item of resultArray) {
   // 刪除字符串中的/符號(hào)
   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);
 // 修改滾動(dòng)條位置
 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ù)報(bào)錯(cuò),報(bào)錯(cuò)原因:內(nèi)容超過最大長度。

前端通過post請(qǐng)求將base64碼傳到服務(wù)端,服務(wù)端直接將base64碼解析為圖片保存至服務(wù)器

從下午2點(diǎn)折騰到晚上6點(diǎn),一直在找Java解析base64圖片存到服務(wù)器的方案,最終選擇了放棄,采用了前端轉(zhuǎn)換方式,這里的問題大概是前端傳base64碼到后端時(shí),http請(qǐng)求會(huì)進(jìn)行轉(zhuǎn)義,導(dǎo)致后端解析得到的base64碼是錯(cuò)誤的,所以一直沒有成功。

項(xiàng)目地址:chat-system

總結(jié)

以上所述是小編給大家介紹的Vue解析剪切板圖片并實(shí)現(xiàn)發(fā)送功能,希望對(duì)大家有所幫助!

相關(guān)文章

  • vue項(xiàng)目環(huán)境搭建?啟動(dòng)?移植操作示例及目錄結(jié)構(gòu)分析

    vue項(xiàng)目環(huán)境搭建?啟動(dòng)?移植操作示例及目錄結(jié)構(gòu)分析

    這篇文章主要介紹了vue項(xiàng)目環(huán)境搭建、啟動(dòng)、項(xiàng)目移植、項(xiàng)目目錄結(jié)構(gòu)分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • vuejs路由的傳參及路由props配置詳解

    vuejs路由的傳參及路由props配置詳解

    最近在學(xué)習(xí)vue router的傳參,所以下面這篇文章主要給大家介紹了關(guān)于vuejs路由的傳參及路由props配置的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • vue實(shí)現(xiàn)勻速輪播效果

    vue實(shí)現(xiàn)勻速輪播效果

    這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)勻速輪播效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • Vue的樣式綁定詳解

    Vue的樣式綁定詳解

    這篇文章主要為大家詳細(xì)介紹了Vue的樣式綁定,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • Electron主進(jìn)程(Main?Process)與渲染進(jìn)程(Renderer?Process)通信詳解

    Electron主進(jìn)程(Main?Process)與渲染進(jìn)程(Renderer?Process)通信詳解

    這篇文章主要介紹了Electron主進(jìn)程(Main?Process)與渲染進(jìn)程(Renderer?Process)通信,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Vue?2?和?Vue?3?中?toRefs函數(shù)的不用用法

    Vue?2?和?Vue?3?中?toRefs函數(shù)的不用用法

    Vue?是一款流行的JavaScript?框架,用于構(gòu)建用戶界面,在Vue2和?Vue3中,都存在一個(gè)名為toRefs的函數(shù),但其行為在這兩個(gè)版本中有所不同,這篇文章主要介紹了Vue2和Vue3中toRefs的區(qū)別,需要的朋友可以參考下
    2023-08-08
  • 淺談Vue頁面級(jí)緩存解決方案feb-alive (下)

    淺談Vue頁面級(jí)緩存解決方案feb-alive (下)

    這篇文章主要介紹了淺談Vue頁面級(jí)緩存解決方案feb-alive(下),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • vue 計(jì)算屬性和偵聽器的使用小結(jié)

    vue 計(jì)算屬性和偵聽器的使用小結(jié)

    這篇文章主要介紹了vue 計(jì)算屬性和偵聽器的使用小結(jié),幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下
    2021-01-01
  • vue中遇到的坑之變化檢測問題(數(shù)組相關(guān))

    vue中遇到的坑之變化檢測問題(數(shù)組相關(guān))

    這篇文章主要介紹了vue中遇到的坑之變化檢測問題(數(shù)組相關(guān)) ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • VUE寫一個(gè)簡單的表格實(shí)例

    VUE寫一個(gè)簡單的表格實(shí)例

    在本篇文章里小編給大家整理的是關(guān)于VUE中表格的寫法實(shí)例以及相關(guān)知識(shí)點(diǎn)內(nèi)容,需要的朋友們可以參考下。
    2019-08-08

最新評(píng)論