← HIPVOGUE | 代码

Chrome插件:点击按钮复制选中的文本

· 发表评论

平时浏览网页,经常需要复制网页中的文本,常规做法是用键盘快捷键,但有时不想按键盘,只想通过点击鼠标完成。也就是:鼠标单机滑动选中文本后,在文本下面弹出一个复制按钮。点击复制按钮,选中的文本将被复制到剪贴板中.

项目结构

CopyText/
│
├── manifest.json
├── background.js
├── content.js
├── popup.js
├── popup.html
└── icon.png

1. manifest.json

这是插件的配置文件,定义了插件的基本信息和权限。

{
  "manifest_version": 3,
  "name": "CopyText",
  "version": "1.0",
  "description": "选中文本后显示复制按钮,点击即可复制文本到剪贴板。",
  "icons": {
    "16": "icon.png",
    "48": "icon.png",
    "128": "icon.png"
  },
  "permissions": [
    "clipboardWrite",
    "activeTab",
    "scripting"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_popup": "popup.html",
    "default_icon": "icon.png"
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"]
    }
  ]
}

说明

  • manifest_version: 使用 3 表示 Chrome 插件的 Manifest V3 版本。
  • permissions:

    • clipboardWrite:允许插件写入剪贴板。
    • activeTab 和 scripting:用于在活动标签页上执行脚本(Manifest V3 需要)。
  • background: 使用 background.js 作为后台服务工作者。
  • action: 定义了插件图标的行为,设置了默认的弹出页面 popup.html
  • content_scripts: 注入 content.js 到所有网页中。

2. background.js

在这个简单的插件中,后台脚本可能不需要执行任何操作,但为了遵循 Manifest V3 的要求,我们保留此文件为空。

// background.js
// 当前不需要任何后台逻辑

3. content.js

这是插件的主要内容脚本,负责检测文本选中、显示“Copy”按钮、处理复制操作以及显示提示。

let copyButton = null;
let tooltip = null;

// 创建复制按钮
function createCopyButton() {
  copyButton = document.createElement('button');
  copyButton.innerText = 'Copy';
  copyButton.style.position = 'absolute';
  copyButton.style.padding = '5px 10px';
  copyButton.style.fontSize = '14px';
  copyButton.style.backgroundColor = '#4CAF50';
  copyButton.style.color = '#fff';
  copyButton.style.border = 'none';
  copyButton.style.borderRadius = '4px';
  copyButton.style.cursor = 'pointer';
  copyButton.style.zIndex = '1000';
  copyButton.style.display = 'none';
  copyButton.style.boxShadow = '0 2px 6px rgba(0,0,0,0.2)';
  copyButton.style.transition = 'opacity 0.3s';
  document.body.appendChild(copyButton);

  // 创建提示框
  tooltip = document.createElement('div');
  tooltip.innerText = 'copied';
  tooltip.style.position = 'absolute';
  tooltip.style.padding = '5px 10px';
  tooltip.style.fontSize = '12px';
  tooltip.style.backgroundColor = '#333';
  tooltip.style.color = '#fff';
  tooltip.style.borderRadius = '4px';
  tooltip.style.opacity = '0';
  tooltip.style.transition = 'opacity 0.3s';
  tooltip.style.zIndex = '1000';
  document.body.appendChild(tooltip);

  // 绑定复制按钮的点击事件
  copyButton.addEventListener('click', () => {
    const selectedText = window.getSelection().toString();
    if (selectedText) {
      navigator.clipboard.writeText(selectedText).then(() => {
        showTooltip();
        copyButton.style.display = 'none';
      }).catch(err => {
        console.error('复制失败:', err);
      });
    }
  });
}

// 显示复制提示
function showTooltip() {
  const rect = copyButton.getBoundingClientRect();
  tooltip.style.top = `${rect.top - 30 + window.scrollY}px`;
  tooltip.style.left = `${rect.left + window.scrollX}px`;
  tooltip.style.opacity = '1';
  setTimeout(() => {
    tooltip.style.opacity = '0';
  }, 1500);
}

// 计算选中文本末尾的位置
function getSelectionEndPosition() {
  const selection = window.getSelection();
  if (selection.rangeCount === 0) return null;
  const range = selection.getRangeAt(0).cloneRange();
  range.collapse(false); // 将Range设置为结束位置
  const rect = range.getBoundingClientRect();
  return {
    top: rect.bottom + window.scrollY,
    left: rect.right + window.scrollX
  };
}

// 监听鼠标选择事件
document.addEventListener('mouseup', () => {
  setTimeout(() => {
    const selectedText = window.getSelection().toString();
    if (selectedText) {
      const position = getSelectionEndPosition();
      if (position) {
        // 设置按钮的位置
        copyButton.style.top = `${position.top + 5}px`; // 可根据需要调整偏移量
        copyButton.style.left = `${position.left}px`;
        copyButton.style.display = 'block';
        copyButton.style.opacity = '1';
      } else {
        copyButton.style.display = 'none';
      }
    } else {
      copyButton.style.display = 'none';
    }
  }, 10);
});

// 当点击页面其他部分时隐藏按钮
document.addEventListener('click', (e) => {
  if (copyButton && !copyButton.contains(e.target)) {
    copyButton.style.display = 'none';
  }
});

// 初始化
createCopyButton();

说明

  • createCopyButton: 创建一个隐藏的“Copy”按钮和一个提示框。按钮样式可以根据需要进行调整。
  • showTooltip: 在按钮附近显示“copied”提示,并在1.5秒后消失。
  • 事件监听: 监听 mouseup 事件,当用户完成文本选择后,显示“Copy”按钮。如果没有选中文本,则隐藏按钮。

4. popup.html

这是插件图标点击后显示的弹出页面。根据功能需求,这里可以简单设置一个说明或者留空。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>CopyText</title>
  <style>
    body {
      min-width: 200px;
      min-height: 100px;
      font-family: Arial, sans-serif;
      padding: 10px;
    }
    h3 {
      margin-top: 0;
    }
  </style>
</head>
<body>
  <h3>CopyText 插件</h3>
  <p>选中文本后会出现“Copy”按钮,点击即可复制文本。</p>
</body>
</html>

说明

  • 提供了一个简单的用户界面,说明插件的基本功能。

5. icon.png

这是插件的图标文件。你需要准备一个图标文件(建议尺寸为128x128像素),并保存为 icon.png 放在项目根目录下。如果没有现成的图标,可以使用在线工具生成一个简单的图标。

打包与安装

完成上述文件后,按照以下步骤在 Chrome 中加载插件:

  1. 打开 Chrome 浏览器,输入 chrome://extensions/ 并回车。
  2. 打开右上角的“开发者模式”。
  3. 点击“加载已解压的扩展程序”按钮。
  4. 选择你的 CopyText 项目文件夹。
  5. 现在,你应该可以在浏览器的扩展栏看到 CopyText 的图标。

测试插件

  1. 打开任意一个网页。
  2. 选中文本后,页面下方应该会出现一个“Copy”按钮。
  3. 点击“Copy”按钮,选中的文本将被复制到剪贴板,并在按钮附近显示“copied”提示。

注意事项

  • 权限:确保 manifest.json 中的权限足够但不过度,避免请求不必要的权限。
  • 样式调整:根据需要调整 content.js 中“Copy”按钮和提示框的样式,以适应不同网页的布局。
  • 兼容性:虽然指定了 Chrome 版本 128.0.xxxx,但请尽量使插件在其他版本的 Chrome 也能正常工作。

# 插件# Chrome# 复制

添加新评论