You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome扩展开发:实现选中文本触发Popover并保存文本

实现选中文本触发悬浮Popover并保存文本

核心修改思路

  • 移除原生模态框(dialog),改为创建跟随选中文本区域定位的悬浮Popover
  • 通过选区的getBoundingClientRect()获取位置,精准定位Popover
  • 添加保存按钮并绑定消息传递逻辑,实现文本保存
  • 优化事件监听,避免重复创建Popover或误关闭

修改后的完整Content.js代码

// Content.js
import type { PlasmoCSConfig } from "plasmo"
import { useEffect, useState } from "react"

const getSelectedText = () => window.getSelection().toString().trim()

// 创建并渲染Popover
const renderPopover = (selectionRect, selectedText) => {
  // 先移除已存在的Popover
  const existingPopover = document.getElementById("text-select-popover")
  if (existingPopover) {
    existingPopover.remove()
  }

  // 创建Popover容器
  const popover = document.createElement("div")
  popover.id = "text-select-popover"
  popover.style.cssText = `
    position: fixed;
    top: ${selectionRect.top - 40}px;
    left: ${selectionRect.left + (selectionRect.width / 2) - 75}px;
    background: #fff;
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 8px 12px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.15);
    z-index: 999999;
    display: flex;
    gap: 8px;
    align-items: center;
  `

  // 添加文本和保存按钮
  const textSpan = document.createElement("span")
  textSpan.textContent = "保存选中内容"
  textSpan.style.fontSize = "14px"

  const saveBtn = document.createElement("button")
  saveBtn.textContent = "保存"
  saveBtn.style.cssText = `
    padding: 4px 8px;
    background: #007bff;
    color: #fff;
    border: none;
    border-radius: 2px;
    cursor: pointer;
    font-size: 14px;
  `

  // 保存按钮点击事件:发送消息到后台
  saveBtn.addEventListener("click", async () => {
    await chrome.runtime.sendMessage({
      type: "SAVE_SELECTED_TEXT",
      text: selectedText
    })
    popover.remove() // 保存后关闭Popover
  })

  popover.appendChild(textSpan)
  popover.appendChild(saveBtn)
  document.body.appendChild(popover)

  // 点击页面其他区域关闭Popover
  const closePopover = (e) => {
    if (!popover.contains(e.target)) {
      popover.remove()
      document.removeEventListener("click", closePopover)
    }
  }
  document.addEventListener("click", closePopover)
}

// 监听文本选中事件
useEffect(() => {
  const handleSelection = () => {
    const selectedText = getSelectedText()
    if (selectedText) {
      const selection = window.getSelection()
      const range = selection.getRangeAt(0)
      const selectionRect = range.getBoundingClientRect()
      renderPopover(selectionRect, selectedText)
    } else {
      // 无选中时移除Popover
      const existingPopover = document.getElementById("text-select-popover")
      existingPopover?.remove()
    }
  }

  // 监听鼠标松开(选中文本后触发)
  document.addEventListener("mouseup", handleSelection)
  // 监听键盘选中文本(比如Ctrl+A)
  document.addEventListener("keyup", handleSelection)

  return () => {
    document.removeEventListener("mouseup", handleSelection)
    document.removeEventListener("keyup", handleSelection)
  }
}, [])

关键细节说明

  • 定位逻辑:通过range.getBoundingClientRect()获取选中文本的矩形区域,将Popover定位在选区上方居中位置,避免遮挡选中内容
  • 样式优化:添加阴影、圆角和合适的层级(z-index),确保Popover在页面最上层且视觉友好
  • 事件优化:使用mouseup和keyup监听选中文本,比原有的click更精准;添加Popover外点击关闭逻辑,同时避免点击Popover内部时误关闭
  • 重复创建处理:每次创建前先移除已存在的Popover,避免页面出现多个悬浮框

后续补充

  1. 若需要更复杂的Popover样式,可以将CSS抽离到单独的样式文件中,通过Plasmo的css配置引入
  2. 保存文本的后台逻辑(比如存储到chrome.storage)需要在background.js中监听SAVE_SELECTED_TEXT类型的消息并处理

内容的提问来源于stack exchange,提问作者dmk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 03:47:40