新建文件夹(如 tab-url-tools-firefox),在其中创建以下 3 个文件:
manifest.json(Firefox 专属配置)

{
  "manifest_version": 3,
  "name": "标签页网址提取",
  "version": "1.0.0",
  "description": "一键获取浏览器所有打开标签页的网址",
  "permissions": ["tabs"],
  "action": {
    "default_title": "查看所有标签页网址",
    "default_popup": "popup.html"
  },
  "browser_specific_settings": {
    "gecko": {
      "id": "tab-url-tool@example.local",
      "strict_min_version": "109.0"
    }
  }
}

说明:browser_specific_settings.gecko.id 是 Firefox 强制要求的扩展唯一标识,格式为邮箱样式可自定义;strict_min_version 表示最低支持 Firefox 109(首个完整支持 MV3 的正式版本)。

popup.html(界面文件)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <style>
    body {
      width: 420px;
      margin: 0;
      padding: 12px 16px;
      font-family: system-ui, -apple-system, sans-serif;
      font-size: 13px;
    }
    .header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 10px;
      padding-bottom: 8px;
      border-bottom: 1px solid #eee;
    }
    .title {
      font-weight: 600;
      font-size: 14px;
    }
    .copy-btn {
      padding: 4px 10px;
      border: 1px solid #d0d7de;
      border-radius: 4px;
      background: #f6f8fa;
      cursor: pointer;
      font-size: 12px;
    }
    .copy-btn:hover {
      background: #eaeef2;
    }
    .url-list {
      max-height: 360px;
      overflow-y: auto;
      margin: 0;
      padding: 0;
      list-style: none;
    }
    .url-item {
      padding: 6px 0;
      border-bottom: 1px solid #f5f5f5;
      word-break: break-all;
      line-height: 1.4;
      color: #24292f;
    }
    .url-item:last-child {
      border-bottom: none;
    }
    .count {
      color: #656d76;
      font-size: 12px;
      font-weight: normal;
    }
  </style>
</head>
<body>
  <div class="header">
    <span class="title">全部标签页网址 <span class="count" id="count"></span></span>
    <button class="copy-btn" id="copyBtn">复制全部</button>
  </div>
  <ul class="url-list" id="urlList"></ul>
  <script src="popup.js"></script>
</body>
</html>

popup.js(Firefox 原生 Promise 写法)

Firefox 的 browser.* API 原生返回 Promise,使用 async/await 写法更简洁:

const urlList = document.getElementById('urlList');
const countEl = document.getElementById('count');
const copyBtn = document.getElementById('copyBtn');
let allUrls = [];

// 页面加载后获取所有标签页
document.addEventListener('DOMContentLoaded', async () => {
  const tabs = await browser.tabs.query({});
  allUrls = tabs.map(tab => tab.url);
  countEl.textContent = `(共 ${tabs.length} 个)`;

  // 渲染列表
  tabs.forEach((tab, index) => {
    const li = document.createElement('li');
    li.className = 'url-item';
    li.textContent = `${index + 1}. ${tab.url}`;
    urlList.appendChild(li);
  });
});

// 一键复制全部网址
copyBtn.addEventListener('click', async () => {
  const text = allUrls.join('\n');
  try {
    await navigator.clipboard.writeText(text);
    copyBtn.textContent = '已复制';
    setTimeout(() => {
      copyBtn.textContent = '复制全部';
    }, 1500);
  } catch (err) {
    alert('复制失败,请手动选择复制');
  }
});

安装
打开 Firefox,地址栏输入 about:debugging#/runtime/this-firefox 回车,进入扩展调试页面
点击页面中的临时加载附加组件按钮
在文件选择窗口中,找到扩展文件夹,选中里面的 manifest.json 文件(注意:Firefox 是选文件,不是选文件夹,和 Chrome 不同),确认即可
安装成功后,工具栏会出现扩展图标,点击即可使用

⚠️ 注意事项:

以上方式安装的是临时扩展,Firefox 完全关闭重启后会自动失效,适合测试使用
如需永久安装,可将扩展提交到 Firefox 附加组件商店签名,或使用 Firefox 开发者版 / 夜间版,在 about:config 中设置 xpinstall.signatures.required 为 false 后安装未签名扩展

如果加入日期和title提取

manifest.json 无需改动,tabs 权限本身支持读取标签页标题,我们只需要修改 popup.html 和 popup.js,新增当前提取日期时间和网页标题的展示与复制。以下代码同时兼容 Firefox 和 Chrome/Edge。

  1. popup.html(更新后)
    调整了布局,顶部显示提取时间和标签页总数,每个标签页分开展示标题和网址,层级更清晰:
    popup.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <style>
    body {
      width: 450px;
      margin: 0;
      padding: 12px 16px;
      font-family: system-ui, -apple-system, sans-serif;
      font-size: 13px;
    }
    .header {
      margin-bottom: 10px;
      padding-bottom: 8px;
      border-bottom: 1px solid #eee;
    }
    .header-top {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 6px;
    }
    .title {
      font-weight: 600;
      font-size: 14px;
    }
    .meta {
      color: #656d76;
      font-size: 12px;
    }
    .copy-btn {
      padding: 4px 10px;
      border: 1px solid #d0d7de;
      border-radius: 4px;
      background: #f6f8fa;
      cursor: pointer;
      font-size: 12px;
    }
    .copy-btn:hover {
      background: #eaeef2;
    }
    .url-list {
      max-height: 380px;
      overflow-y: auto;
      margin: 0;
      padding: 0;
      list-style: none;
    }
    .url-item {
      padding: 8px 0;
      border-bottom: 1px solid #f5f5f5;
      line-height: 1.4;
    }
    .url-item:last-child {
      border-bottom: none;
    }
    .tab-title {
      font-weight: 500;
      color: #1f2328;
      margin-bottom: 3px;
      word-break: break-all;
    }
    .tab-url {
      color: #656d76;
      font-size: 12px;
      word-break: break-all;
    }
  </style>
</head>
<body>
  <div class="header">
    <div class="header-top">
      <span class="title">标签页信息汇总</span>
      <button class="copy-btn" id="copyBtn">复制全部</button>
    </div>
    <div class="meta">
      提取时间:<span id="extractTime"></span>
      <span> · 共 <span id="count"></span> 个标签页</span>
    </div>
  </div>
  <ul class="url-list" id="urlList"></ul>
  <script src="popup.js"></script>
</body>
</html>

popup.js


const urlList = document.getElementById('urlList');
const countEl = document.getElementById('count');
const timeEl = document.getElementById('extractTime');
const copyBtn = document.getElementById('copyBtn');

// 自动兼容 Firefox / Chrome
const api = typeof browser !== 'undefined' ? browser : chrome;

// 格式化日期时间为 YYYY-MM-DD HH:mm:ss
function formatDateTime(date) {
  const y = date.getFullYear();
  const m = String(date.getMonth() + 1).padStart(2, '0');
  const d = String(date.getDate()).padStart(2, '0');
  const h = String(date.getHours()).padStart(2, '0');
  const min = String(date.getMinutes()).padStart(2, '0');
  const s = String(date.getSeconds()).padStart(2, '0');
  return `${y}-${m}-${d} ${h}:${min}:${s}`;
}

// 页面加载后获取数据并渲染
document.addEventListener('DOMContentLoaded', async () => {
  const now = new Date();
  const extractTime = formatDateTime(now);
  timeEl.textContent = extractTime;

  // 获取所有标签页
  const tabs = await api.tabs.query({});
  countEl.textContent = tabs.length;

  // 渲染列表
  tabs.forEach((tab, index) => {
    const li = document.createElement('li');
    li.className = 'url-item';

    const titleDiv = document.createElement('div');
    titleDiv.className = 'tab-title';
    titleDiv.textContent = `${index + 1}. ${tab.title || '无标题'}`;

    const urlDiv = document.createElement('div');
    urlDiv.className = 'tab-url';
    urlDiv.textContent = tab.url;

    li.appendChild(titleDiv);
    li.appendChild(urlDiv);
    urlList.appendChild(li);
  });
});

// 一键复制全部信息
copyBtn.addEventListener('click', async () => {
  const tabs = await api.tabs.query({});
  const lines = [];
  
  lines.push(`提取时间:${timeEl.textContent}`);
  lines.push('------------------------------');
  
  tabs.forEach((tab, index) => {
    lines.push(`${index + 1}. ${tab.title || '无标题'}`);
    lines.push(tab.url);
    lines.push(''); // 空行分隔
  });

  const text = lines.join('\n');
  try {
    await navigator.clipboard.writeText(text);
    copyBtn.textContent = '已复制';
    setTimeout(() => {
      copyBtn.textContent = '复制全部';
    }, 1500);
  } catch (err) {
    alert('复制失败,请手动选择复制');
  }
});

manifest.json

{
  "manifest_version": 3,
  "name": "标签页信息提取",
  "version": "1.1.0",
  "description": "一键获取所有标签页的标题、网址与提取时间",
  "permissions": ["tabs"],
  "action": {
    "default_title": "查看标签页信息",
    "default_popup": "popup.html"
  },
  "browser_specific_settings": {
    "gecko": {
      "id": "tab-url-tool@example.local",
      "strict_min_version": "109.0"
    }
  }
}


效果说明

弹窗顶部会显示本次提取的精确日期时间(年 - 月 - 日 时:分: 秒)和标签页总数
每个标签页先显示网页标题,下方显示对应网址,层级清晰
点击「复制全部」会把提取时间、所有标签页的标题 + 网址按格式复制,粘贴到笔记 / 文档中直接可用
加载中、无标题的页面会自动显示「无标题」兜底,不会报错
Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐