左键选择v-html绑定的文本内容,松开鼠标后出现复制弹窗

HTML

html 复制代码
<template>
  <div class="report_generate_wrap" id="parentElement">
    <div ref="textContainer" @mouseup="mouseUp" v-html="textContent"></div>
    <div v-if="showCopyPopup" :style="copyPopupStyle" class="copy-popup">
      <p>已选中文本,点击复制:</p>
      <button @click="copyText" style="margin-right: 10px">复制</button>
      <button @click="hideCopyPopup">取消</button>
    </div>
  </div>
</template>

JS

javascript 复制代码
data() {
    return {
      textContent: "这是一段示例文本,你可以尝试选中它。",
      showCopyPopup: false,
      selectedText: "",
      lastMousePosition: { x: 0, y: 0 },
      previousSelectedText: "",
    };
  },

computed: {
  copyPopupStyle() {
    return {
      position: "absolute",
      left: `${this.lastMousePosition.x + 20}px`, // 假设弹窗距离鼠标右侧20px
      top: `${this.lastMousePosition.y}px`,
      transform: "translateY(-50%)", // 垂直居中
    };
  },
},

mounted() {
  window.addEventListener("click", this.handleGlobalClick);
},

beforeDestroy() {
  window.removeEventListener("click", this.handleGlobalClick);
},

methods: {
  handleGlobalClick(event) {
    // 如果点击事件不是发生在textContainer元素内,则隐藏复制弹窗
    if (!this.$refs.textContainer.contains(event.target)) {
      this.showCopyPopup = false;
    }
  },
  mouseUp(event) {
    console.log("鼠标松开");
    this.updateMousePosition(event);
    const selection = window.getSelection();
    if (selection.rangeCount > 0) {
      const range = selection.getRangeAt(0);
      this.selectedText = range.toString().trim();

      // 检查当前选中的文本是否与之前选中的文本不同
      if (this.selectedText !== this.previousSelectedText) {
        if (this.selectedText !== "") {
          this.showCopyPopup = true;
        } else {
          this.showCopyPopup = false;
        }
        // 更新之前选中的文本
        this.previousSelectedText = this.selectedText;
      } else {
        // 如果相同,则不显示复制弹出框
        this.showCopyPopup = false;
      }
    } else {
      this.showCopyPopup = false;
      this.selectedText = "";
      this.previousSelectedText = ""; // 清除之前选中的文本
    }
  },
  updateMousePosition(event) {
    const parentElement = document.getElementById("parentElement");
    this.lastMousePosition = {
      x: event.clientX - parentElement.getBoundingClientRect().left,//鼠标相对于父元素的位置
      y: event.clientY,
    };
  },

  copyText() {
    const textarea = document.createElement("textarea");
    textarea.value = this.selectedText;
    document.body.appendChild(textarea);
    textarea.select();
    document.execCommand("copy");
    document.body.removeChild(textarea);
    this.hideCopyPopup();
  },
  hideCopyPopup() {
    this.showCopyPopup = false;
  },
}

CSS

javascript 复制代码
<style scoped lang="less">
.copy-popup {
  background-color: white;
  border: 1px solid #ccc;
  padding: 10px;
  z-index: 1000;
}
</style>
相关推荐
majingming1232 小时前
FUNCTION
java·前端·javascript
A_nanda3 小时前
Vue项目升级
前端·vue3·vue2
SuperEugene3 小时前
Axios 接口请求规范实战:请求参数 / 响应处理 / 异常兜底,避坑中后台 API 调用混乱|API 与异步请求规范篇
开发语言·前端·javascript·vue.js·前端框架·axios
abigale033 小时前
【浏览器 API / 网络请求 / 文件处理】前端文件上传全流程:从基础上传到断点续传
前端·typescript·文件上传·vue cli
子兮曰3 小时前
Bun v1.3.11 官方更新全整理:新增功能、关键修复与升级验证
javascript·node.js·bun
Setsuna_F_Seiei4 小时前
AI 对话应用之页面滚动交互的实现
前端·javascript·ai编程
新缸中之脑4 小时前
追踪来自Agent的Web 流量
前端
wefly20174 小时前
从使用到原理,深度解析m3u8live.cn—— 基于 HLS.js 的 M3U8 在线播放器实现
java·开发语言·前端·javascript·ecmascript·php·m3u8
英俊潇洒美少年5 小时前
vue如何实现react useDeferredvalue和useTransition的效果
前端·vue.js·react.js
kyriewen116 小时前
给浏览器画个圈:CSS contain 如何让页面从“卡成PPT”变“丝滑如德芙”
开发语言·前端·javascript·css·chrome·typescript·ecmascript