实现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  

 

posted @ 2024-08-26 15:17  沁猿春  阅读(61)  评论(0编辑  收藏  举报