html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>聊天框</title>
<style>
body,
html {
text-align: center;
}
#editDiv {
width: 600px;
display: inline-block;
min-height: 100px;
background: #fff;
border-radius: 10px;
line-height: 20px;
padding: 10px;
font-size: 14px;
color: #666;
resize: none;
outline: none;
overflow-y: auto;
}
#editDiv {
border: 1px solid #333;
border-color: rgba(169, 169, 169, 1);
text-align: left;
}
/* 隐藏 Chrome、Safari 和 Opera 的滚动条 */
#editDiv::-webkit-scrollbar {
display: none;
}
/* 隐藏 IE、Edge 和 Firefox 的滚动条 */
#editDiv {
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
}
#msg {
width: 1024px;
min-height: 100px;
overflow: hidden;
border: 1px solid #000;
margin: 10px auto;
}
p {
border: 1px solid #666;
background-color: #666;
width: 50%;
margin: 5px auto;
}
img {
/* border: 1px solid #666; */
margin: 5px auto;
}
</style>
<script src="./paste.js"></script>
</head>
<body>
<div id="editDiv" contenteditable="true"></div>
<button onclick="send()">发送</button>
<div id="msg"></div>
<script>
var edit = document.getElementById('editDiv');
edit.focus()
// 监听粘贴事件
document.querySelector('#editDiv').addEventListener('paste', (e) => {
onPaste(e).then((res) => {
console.log(res)
})
}, false);
function send() {
// 获取输入框的内容,发送消息
var edit = document.getElementById('editDiv');
var msg = document.getElementById('msg');
// 分离出图片和文字
let children = edit.childNodes;
if (children.length == 0) return alert("消息不能为空");
// 为每个子元素创建一个 Promise
let promises = [];
let text = "";
children.forEach(item => {
console.log(item.nodeName)
if (item.tagName && item.tagName.toLowerCase() === 'img') {
promises.push(sendImg(msg, item.src));
} else if (item.nodeName == '#text') {
//promises.push(sendText(msg, item.data));
text += item.data
}
});
if (typeof text == 'string' && text.length > 0) promises.push(sendText(msg, text));
// 使用 Promise.all 等待所有消息发送完成
Promise.all(promises)
.then(() => {
// 清空输入框
edit.innerHTML = "";
})
.catch(error => {
console.error('发送消息出错:', error);
});
}
function sendImg(msg, src) {
return new Promise((resolve, reject) => {
let img = document.createElement('img');
img.onload = function () {
msg.appendChild(img);
resolve();
};
img.onerror = function () {
reject(new Error('图片加载失败'));
};
img.src = src;
});
}
function sendText(msg, text) {
return new Promise((resolve, reject) => {
var para = document.createElement("p");
para.innerText = text;
msg.appendChild(para);
resolve();
});
}
</script>
</body>
</html>
paste.js代码
// 定义粘贴函数
const onPaste = (e) => {
e.preventDefault();//拦截默认粘贴操作
e.stopPropagation();//防止冒泡
// var editDiv = document.getElementById('editDiv');
var cbd = e.clipboardData;
var ua = window.navigator.userAgent;
// 剪贴板没数据,则直接返回
if (!e.clipboardData || !e.clipboardData.items) {
return;
}
// Mac平台下Chrome49版本以下 复制Finder中的文件的Bug Hack掉
if (cbd.items && cbd.items.length === 2 && cbd.items[0].kind === "string" && cbd.items[1].kind === "file" &&
cbd.types && cbd.types.length === 2 && cbd.types[0] === "text/plain" && cbd.types[1] === "Files" &&
ua.match(/Macintosh/i) && Number(ua.match(/Chrome\/(\d{2})/i)[1]) < 49) {
return;
}
return new Promise((resovle, reject) => {
for (let i = 0; i < cbd.items.length; i++) {
const item = cbd.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 if (item.kind === 'string') {
let str = cbd.getData('text')
// 处理文字
handleText(str, (data) => {
resovle(data)
})
} else {
reject(new Error('不支持粘贴该类型'));
}
}
})
}
// 处理图片
function handleImage(file, callback, maxWidth = 50, maxHeight = 50) {
if (!file || !/(?:png|jpg|jpeg|gif)/i.test(file.type)) {
callback('图片格式不支持')
return;
}
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
const result = this.result;
let img = new Image();
img.onload = function () {
let compressedDataUrl = compressImage(img, file.type, maxWidth, maxHeight, true);
let url = compressImage(img, file.type, maxWidth, maxHeight, false);
addImageToPage(compressedDataUrl);
img = null;
callback({
data: file,
compressedDataUrl,
url,
type: 'image'
})
};
img.src = result;
};
}
// 压缩图片函数
function compressImage(img, type, maxWidth, maxHeight, flag = true) {
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
// 计算压缩后的宽高比例
let ratio = 1;
if (flag && (img.width > maxWidth || img.height > maxHeight)) {
ratio = Math.min(maxWidth / img.width, maxHeight / img.height);
}
// 设置canvas的宽高
canvas.width = img.width * ratio;
canvas.height = img.height * ratio;
// 绘制图片到canvas
// ctx.fillStyle = '#fff';
// ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// 将canvas转换为base64格式的图片数据
let base64Data = canvas.toDataURL(type, 0.75);
if (type === 'image/gif') {
let regx = /(?<=data:image).*?(?=;base64)/; // 正则表示时在用于replace时,根据浏览器的不同,有的需要为字符串
base64Data = base64Data.replace(regx, '/gif');
}
canvas = null;
ctx = null;
return base64Data;
}
//粘贴压缩后的图片到输入框
function addImageToPage(dataUrl) {
let img = document.createElement('img');
img.src = dataUrl;
insertHtmlAtCaret(img)
}
// 粘贴文字
function handleText(str, callback) {
let textNode = document.createTextNode(str)
insertHtmlAtCaret(textNode)
callback({
data: str,
type: 'string'
})
}
/**
*
* @param {*} textNode 插入的node
*/
function insertHtmlAtCaret(textNode) {
let sel, range;
if (window.getSelection) {
// IE9 and non-IE
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
let frag = document.createDocumentFragment();
let lastNode = frag.appendChild(textNode);
range.insertNode(frag);
if (lastNode) {
range = range.cloneRange();
range.setStartAfter(lastNode);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
}
} else if (document.selection && document.selection.type != "Control") {
// IE < 9
document.selection.createRange().pasteHTML(textNode);
}
}
支持粘贴图片和文字,粘贴后,光标默认到末尾。点击发送,会将图片文字新增到id为msg的div并清空输入框。案例已调试好,可以根据自己的需求更改
--5.7--
优化:在中间插入内容时,文字应该粘贴到光标位置,光标移到粘贴文本末尾