Vue實現(xiàn)輸入框回車發(fā)送和粘貼文本與圖片功能
上一篇中,我們初步新建了一個可“雙向綁定”的聊天輸入框,結(jié)合實際使用的場景,如果僅僅只是實現(xiàn)了“雙向綁定”還不夠,還必須處理粘貼文字、圖片等功能。本文就在此基礎(chǔ)上,繼續(xù)探討如何實現(xiàn)回車發(fā)送、粘貼文本(包括HTML)、粘貼圖片等功能。話不多說,咱們開整。contenteditable的元素如何實現(xiàn)“雙向綁定”?
實現(xiàn)回車發(fā)送
在一個可編輯元素中,默認回車就是換行。但是如果我們要實現(xiàn)回車是“發(fā)送”的功能,需要怎么處理呢?
思路:監(jiān)聽鍵盤事件,如果判斷用戶按下的是回車鍵,則執(zhí)行發(fā)送邏輯,并阻止瀏覽器的默認行為。
實現(xiàn)起來也可以有兩種方式:
event
<div class="input-box" contenteditable @keydown="handleKeydown"></div>
...
handleKeydown(event) {
if (event.shiftKey && event.keyCode === 13) {
document.execCommand('insertLineBreak'); // 換行
} else if (event.keyCode === 13) { // 回車鍵
console.log("回車發(fā)送");
event.preventDefault();
return false;
}
}這樣就可以實現(xiàn)回車發(fā)送。但是這種方式是有問題的,具體如下:
- 如果持續(xù)按下回車鍵,將會一直觸發(fā)
- 其他鍵 + 回車鍵也會觸發(fā)此判斷
- 需要額外增加邏輯,否則輸入框?qū)⒉豢蓳Q行
那有沒有什么辦法是可以解決的呢,對于Vue項目來說,可以借助按鍵修飾符
按鍵修飾符
<div class="input-box" contenteditable @keyup.enter.exact="submit" @keydown.enter.exact="handleKeydown"></div>
...
},
submit() {
console.log('回車發(fā)送');
},
handleKeydown(event) {
event.preventDefault();
return false;
},按鍵修飾符的具體文檔可參考官網(wǎng):事件處理 — Vue.js (vuejs.org),本處只重點說明.extra修飾符。.extra可以精確控制按鍵組合,結(jié)合keyup和keydown,上述代碼翻譯過來就是:只有一個回車鍵時,并且回彈起來才會觸發(fā)“回車發(fā)送”;如果只有一個回車鍵,并且按下,則阻止瀏覽器默認事件。這樣就可以實現(xiàn)“回車發(fā)送”。也許有人會問,換行怎么辦。答案就是使用shift + enter,這也是默認的換行。如果不喜歡shift+enter就需要自己處理換行了。
優(yōu)點
- 使用方式簡單
- 可使用默認的方式換行
粘貼文本
粘貼文本不是直接使用ctrl + v嘛,這都不知道?話是這么說,但是如果我們相對粘貼的文本做些處理,直接使用ctrl + v就不合適了,而且后面還會用來粘貼圖片。想要直接粘貼圖片并顯示,還沒有原生輸入框可做到吧。本處需要使用paste事件,也就是專門處理粘貼的。由于我們是要手動插入數(shù)據(jù),因此需要阻止默認操作,需要借助prevent事件修飾符。
paste.prevent
<div class="input-box" contenteditable @paste.prevent="onPaste"></div>
...
import onPaste from '@/utils/onPaste.js'; // 引入專門處理粘貼的方法
...
// 注意是異步處理
async onPaste(event) {
const result = await onPaste(event); // 傳入粘貼事件
console.log('處理后的數(shù)據(jù)', result);
// 插入文本
document.execCommand('insertText', false, result.data);
}重點來了
新建onPaste.js,用來處理文本和圖片的粘貼
// onPaste.js
// 定義粘貼函數(shù)
const onPaste = (event) => {
// 剪貼板沒數(shù)據(jù),則直接返回
if (!event.clipboardData || !event.clipboardData.items) {
return;
}
// 封裝Promise
return new Promise((resovle, reject) => {
// 遍歷剪貼板
for(let i = 0, len = event.clipboardData.items.length; i < len; i++) {
const item = event.clipboardData.items[i];
if (item.kind === 'string') {
// 方式一,直接返回粘貼的文本數(shù)據(jù)
// let str = event.clipboardData.getData('text');
// resovle({
// data: str
// });
// 方式二,過濾掉粘貼的文本中存在的html標(biāo)簽和換行等字符
let reg = /</?.+?/?>/g; // 匹配粘貼文本中的html標(biāo)簽
// 處理字符串類型,參數(shù)為回調(diào)函數(shù)
item.getAsString(str => {
resovle({
data: str.replace(reg, '').replace(/(\r\n)|(\n)/g, '') // 去掉換行符
})
})
} else {
reject(new Error('不支持粘貼該類型'));
}
}
})
}
export default onPaste; // 默認導(dǎo)出方法關(guān)于剪貼板,由幾個概念需要提前了解:clipboardData、DataTransfer、DataTransferItem,具體可參考clipboardData。運行結(jié)果如下:

注:本次復(fù)制的是<div data-v-66ea8951="">父組件修改子組件的值</div>
粘貼圖片
粘貼圖片和粘貼問題有相同之處,也有所不同。最大的不同是顯示圖片,需要獲取圖片的src。在寫代碼前先想幾個問題:
- 圖片展示需要提供src,那么如何獲取src
- 圖片可大可小,如何限制圖片的尺寸,避免超出輸入框范圍
- 圖片像素很高,是否需要壓縮
有了這些問題,就需要一一解決。
- 圖片的壓縮,采用canvas繪制指定尺寸的圖片
base64就由canvas的toDataURL方法獲得- 壓縮時,維持圖片的寬高比
話不多說,先看代碼:
// DivEditable.vue
async onPaste(event) {
const result = await onPaste(event);
console.log('處理后的粘貼數(shù)據(jù)', result);
const imgRegx = /^data:image/png|jpg|jpeg|gif|svg|bmp|tif/; // 支持的圖片格式
if (imgRegx.test(result.compressedDataUrl)) {
// document.execCommand('insertImage', false, result.compressedDataUrl);
const sel = window.getSelection(); // 獲取當(dāng)前光標(biāo)位置
if (sel && sel.rangeCount === 1 && sel.isCollapsed) {
const range = sel.getRangeAt(0);
const img = new Image();
img.src = result.compressedDataUrl; // 使用壓縮后的圖片
range.insertNode(img);
range.collapse(false);
sel.removeAllRanges();
sel.addRange(range);
}
}
}// onPaste.js
// 定義粘貼函數(shù)
const onPaste = (event) => {
...
return new Promise((resovle, reject) => {
for(let i = 0, len = event.clipboardData.items.length; i < len; i++) {
const item = event.clipboardData.items[i];
if (item.kind === 'file') {
const file = item.getAsFile();
if (item.type.match('^image/')) {
// 處理圖片
handleImage(file, (data) => {
resovle(data)
})
} else {
// 其他文件直接返回
resovle({
data: file,
type: 'file'
})
}
} else {
reject(new Error('不支持粘貼該類型'));
}
}
})
}
function handleImage(file, callback, maxWidth = 200) {
console.log('粘貼的圖片', file);
if (!file || !//(?:png|jpg|jpeg|gif)/i.test(file.type)) {
console.log('圖片格式不支持');
return;
}
const reader = new FileReader();
reader.onload = function () {
const result = this.result;
console.log('compressedDataUrl', result);
let img = new Image();
img.onload = function() {
let compressedDataUrl = compress(img, file.type, maxWidth, true);
let url = compress(img, file.type, maxWidth, false);
img = null;
callback({
data: file,
compressedDataUrl,
url,
type: 'image'
})
}
img.src = result;
};
reader.readAsDataURL(file);
}
function compress(img, type, maxWidth, flag) {
let canvas = document.createElement('canvas');
let ctx2 = canvas.getContext('2d');
?
let ratio = img.width / img.height;
let width = img.width, height = img.height;
// 根據(jù)flag判斷是否壓縮圖片
if (flag) {
// 壓縮后的圖片展示在輸入框
width = maxWidth;
height = maxWidth / ratio; // 維持圖片寬高比
}
canvas.width = width;
canvas.height = height;
?
ctx2.fillStyle = '#fff';
ctx2.fillRect(0, 0, canvas.width, canvas.height);
ctx2.drawImage(img, 0, 0, width, height);
?
let base64Data = canvas.toDataURL(type, 0.75);
?
if (type === 'image/gif') {
let regx = /(?<=data:image).*?(?=;base64)/; // 正則表示時在用于replace時,根據(jù)瀏覽器的不同,有的需要為字符串
base64Data = base64Data.replace(regx, '/gif');
}
canvas = null;
ctx2 = null;
return base64Data;
}
export default onPaste;代碼實現(xiàn)效果圖:

插入圖片可使用insertImage命令插入,也可以使用Selection來插入。效果都差不多
壓縮圖片,其實也就是用canvas根據(jù)尺寸比例,重新繪制一張圖片,并獲取圖片的base64
返回數(shù)據(jù)時,需要返回壓縮后和原圖。
如果必須要壓縮圖片,則在handleImage方法中,直接使用FileReader加載圖片后,將base64編碼返回即可。
總結(jié)
本文實現(xiàn)了回車發(fā)送、粘貼文本、粘貼圖片的功能
涉及事件修飾符、按鍵修飾符、剪貼板、canvas等知識
以上就是Vue實現(xiàn)輸入框回車發(fā)送和粘貼文本與圖片功能的詳細內(nèi)容,更多關(guān)于Vue輸入框粘貼文本圖片的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue 解決computed修改data數(shù)據(jù)的問題
今天小編就為大家分享一篇vue 解決computed修改data數(shù)據(jù)的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11
vue項目引入百度地圖BMapGL鼠標(biāo)繪制和BMap輔助工具
這篇文章主要為大家介紹了vue項目引入百度地圖BMapGL鼠標(biāo)繪制和BMap輔助工具的踩坑分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-02-02

