实现div 变成输入框并可复制图片进来
问题描述:
需要做一个类似聊天的输入框,可以复制文字,复制图片
解决方案:
div 设置属性 contenteditable 以及复制粘贴设置 @paste="handlePaste"
HTML 代码:
<div class="reply-box" v-if="isReply"> <div class="reply-input beauty-scroll" contenteditable ref="editableDiv" id="editBox" row="3" @paste="handlePaste" @focus="onFocusEditableDiv" @click="showImageModal" ></div> <div class="reply-btm"> <!-- 必须使用button 按钮能够保持焦点在当前位置的原因是它是一个可聚焦的元素,并且浏览器默认会保留焦点在其上;只有一个图片,焦点会跑到最前面 --> <a-button class="sendImg-btn"> <img src="../../../../assets/img/sendImg.png" alt="" class="sendImg" @click="selectImg"> </a-button> <a-button class="reply-btn" type="primary" size="small" @click="sendMessage" :loading="loading">发送</a-button> </div> </div>
JS 代码 :
/** * 粘贴图片 */ async handlePaste(event) { event.preventDefault(); // 阻止默认的粘贴行为 const clipboardData = event.clipboardData || window.clipboardData; const types = clipboardData.types; if (types.includes("text/plain")) { try { const clp = await navigator.clipboard.readText(); // 将纯文本插入到可编辑区域 this.insertPlainText(clp); } catch (error) { console.error("Failed to read clipboard contents: ", error); } } if (types.includes("Files")) { for (let index = 0; index < clipboardData?.files.length; index++) { const file = clipboardData?.files[index]; const isXls = /\.(jpg|png|jpeg)$/.test(file.name.toLowerCase()); if (isXls) { let options = { file: file, } this.uploadImg(options) } } } }, //插入纯文本 document.execCommand 已被弃用 换成这种方式 insertPlainText(text) { const selection = window.getSelection(); if (selection.getRangeAt && selection.rangeCount) { const range = selection.getRangeAt(0); const doc = range.commonAncestorContainer.ownerDocument; range.deleteContents(); const textNode = doc.createTextNode(text); range.insertNode(textNode); range.setStartAfter(textNode); range.setEndAfter(textNode); selection.removeAllRanges(); selection.addRange(range); } }, //插入图片 insertImageIntoFocusedDiv(url) { const focusedElement = document.activeElement; if ( focusedElement.tagName.toLowerCase() === "div" && focusedElement === this.$refs.editableDiv ) { this.insertImage(focusedElement, url); } else { console.log("没有找到合适的可编辑 div"); } }, insertImage(element, url) { const selection = window.getSelection(); const range = selection.getRangeAt(0); const imgElement = document.createElement("img"); imgElement.src = url; imgElement.style.width = "100px"; imgElement.style.verticalAlign = "baseline"; imgElement.style.cursor = "zoom-in"; range.insertNode(imgElement); // 更新光标位置 const newRange = document.createRange(); newRange.setStartAfter(imgElement); newRange.collapse(true); selection.removeAllRanges(); selection.addRange(newRange); }, //选择图片 selectImg() { this.$refs.editableDiv.focus(); // 确保焦点在可编辑的 div 上 document.querySelector(".avatar-uploader input").click(); }, // 上传前校验 async beforeUpload(file) { const isXls = /\.(xls|jpg|png|jpeg)$/.test(file.name.toLowerCase()); const isLt20M = file.size / 1024 / 1024 < 20; return new Promise((resolve) => { if (!isXls) { this.$message.error("请上传正确格式的文件!"); return false; } if (!isLt20M) { this.$message.error("请上传小于20M的文件!"); return false; } resolve(true); return true; }); }, //图片上传之后 async uploadImg(options) { let result = await this.uploadFile(options.file); let protocol = window.location.protocol; //协议 let domain = window.location.hostname; // 域名 let port = window.location.port ? `:${window.location.port}` : ""; // 端口号 const URL = protocol + "//" + domain + port + "/aldApi" + result.filePath;
//这里拿到文件之后,可根据自己需求来进行文件处理,处理完之后,插入输入框 this.insertImageIntoFocusedDiv(URL); },
点击发送,直接拿到div 输入框里面的html