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

 

posted @   沁猿春  阅读(140)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示