实现div 变成输入框并可复制图片进来
问题描述:
需要做一个类似聊天的输入框,可以复制文字,复制图片
解决方案:
div 设置属性 contenteditable 以及复制粘贴设置 @paste="handlePaste"
HTML 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | < 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 代码 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | /** * 粘贴图片 */ 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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?