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

Vue.js开发Chrome扩展:Background Script传标签页URL问题排查

Chrome扩展问题排查:Background Script监听器无响应,无法传递当前标签URL到Popup页面

我参考示例完成了基于Vue.js的Chrome扩展开发,目前扩展运行正常。现在希望将当前标签页的URL从Background Script传递至Popup页面,但background.js中的onMessage和onClicked监听器无响应,仅onInstalled监听器可正常工作。我是Vue.js和浏览器扩展开发新手,请求帮忙排查代码问题。


现有代码文件

manifest.json

{
    "manifest_version": 3,
    "name": "Random Quote",
    "version": "1.0.0",
    "description": "Browser extension that fetch a random quote from zenquotes.io",
    "host_permissions": ["https://zenquotes.io/"],
    "permissions": ["activeTab", "scripting"],
    "action": {
      "default_popup": "popup.html",
      "default_icon": {
        "16": "images/icon-16x16.png",
        "48": "images/icon-48x48.png",
        "192": "images/icon-128x128.png"
      }
    },
    "background": {
      "service_worker": "js/background.js"
    }
  }

background.js

chrome.runtime.onMessage.addListener(function () {
  console.log("onMessage.addListener");
});

chrome.action.onClicked.addListener(function (tab) {
    console.log("onClicked.addListener");
});

chrome.runtime.onInstalled.addListener(() => {
  console.log('Hello, World!');
});

popup.html

<!DOCTYPE html>
<html lang="en_US">
  <head>
    <title>Random Quote</title>
    <link rel="stylesheet" type="text/css" href="css/popup.css" />
    <meta charset="UTF-8">
  </head>
  <body>
    <div id="app"></div>
    <script src="js/popup.js"></script>
  </body>
</html>

popup.vue

<template>
    <div class="container">
      <h1 class="title text-center">Random Quote</h1>
      <blockquote class="quote-card">
        <p>
          {{ state.quote }}
        </p>

        <cite> {{ state.author }} </cite>
      </blockquote>
      <blockquote class="quote-card">
         here show URL of the currect Tab 
      </blockquote>
    </div>
  </template>
  <script>
  export default {
    data() {
      return {
        state: {
          quote: "",
          author: "",
        },
      };
    },
    async created() {
      try {
        const response = await fetch("https://zenquotes.io/api/random");
        const data = await response.json();

        if (Array.isArray(data) && data.length > 0) {
          this.state.quote = data[0].q; // Extract the quote from the response
          this.state.author = data[0].a;
        } else {
          this.state.quote = "Failed to fetch quote.";
        }
      } catch (error) {
        console.error(error);
        this.state.quote = "Error occurred while fetching quote.";
      }
    },
  };
  </script>

popup.js

import { createApp } from "vue";
import Popup from "./Popup.vue";

console.log("popup.js - 1");
createApp(Popup).mount("#app");
console.log("popup.js - 2");

webpack.mix.js

let mix = require("laravel-mix");

mix
  .setPublicPath("./")
  .sass("src/sass/popup.scss", "dist/css")
  .js("src/js/popup.js","dist/js")
  .js("src/js/background.js","dist/js")
  .vue()
  .copy("src/images/", "dist/images")
  .options({
    processCssUrls: false,
  });

mix-manifest.json

{
    "/dist/js/popup.js": "/dist/js/popup.js",
    "/dist/js/background.js": "/dist/js/background.js",
    "/dist/css/popup.css": "/dist/css/popup.css",
    "/dist/images/icon-128x128.png": "/dist/images/icon-128x128.png",
    "/dist/images/icon-16x16.png": "/dist/images/icon-16x16.png",
    "/dist/images/icon-48x48-off.png": "/dist/images/icon-48x48-off.png",
    "/dist/images/icon-48x48.png": "/dist/images/icon-48x48.png"
}

package.json

{
  "name": "randomquote",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --env=production --config=node_modules/laravel-mix/setup/webpack.config.js",
    "prod": "npm run production"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cross-env": "^7.0.3",
    "laravel-mix": "^6.0.49",
    "postcss": "^8.4.33",
    "sass": "^1.70.0",
    "sass-loader": "^14.0.0",
    "vue": "^3.4.15",
    "vue-loader": "^17.4.2",
    "vue-template-compiler": "^2.7.16"
  }
}

问题原因及修复方案

1. 核心路径错误

你的webpack编译后文件都在dist/目录下,但manifest.json和popup.html里的路径指向了未编译的js/、css/、images/目录,导致Background Service Worker根本没正确加载,所以onMessage和onClicked监听器无法工作。

2. chrome.action.onClicked不触发的原因

当扩展配置了default_popup时,点击扩展图标会直接打开popup,不会触发onClicked事件。该事件仅在扩展没有设置popup时生效,所以这个监听器对你的场景没用,可以移除。

3. Popup未主动发送消息

background.js里的onMessage监听器没有收到任何消息,自然不会有输出,需要在Popup中主动向后台发送请求。

4. 缺少tabs权限

要获取当前标签页URL,必须在manifest中声明tabs权限。


具体修改步骤

① 修正manifest.json路径与权限

{
    "manifest_version": 3,
    "name": "Random Quote",
    "version": "1.0.0",
    "description": "Browser extension that fetch a random quote from zenquotes.io",
    "host_permissions": ["https://zenquotes.io/"],
    "permissions": ["activeTab", "scripting", "tabs"], // 添加tabs权限
    "action": {
      "default_popup": "popup.html",
      "default_icon": {
        "16": "dist/images/icon-16x16.png", // 修正图标路径
        "48": "dist/images/icon-48x48.png",
        "192": "dist/images/icon-128x128.png"
      }
    },
    "background": {
      "service_worker": "dist/js/background.js" // 修正后台脚本路径
    }
  }

② 修正popup.html资源路径

<!DOCTYPE html>
<html lang="en_US">
  <head>
    <title>Random Quote</title>
    <link rel="stylesheet" type="text/css" href="dist/css/popup.css" /> <!-- 修正CSS路径 -->
    <meta charset="UTF-8">
  </head>
  <body>
    <div id="app"></div>
    <script src="dist/js/popup.js"></script> <!-- 修正JS路径 -->
  </body>
</html>

③ 更新background.js,添加消息响应逻辑

// 监听来自Popup的消息,返回当前标签URL
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  console.log("收到Popup消息:", request);
  if (request.type === "GET_CURRENT_TAB_URL") {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      sendResponse({ url: tabs.length > 0 ? tabs[0].url : "无法获取标签URL" });
    });
    // 异步响应需返回true
    return true;
  }
});

chrome.runtime.onInstalled.addListener(() => {
  console.log('Hello, World!');
});

④ 修改Popup.vue,添加获取URL的逻辑

<template>
    <div class="container">
      <h1 class="title text-center">Random Quote</h1>
      <blockquote class="quote-card">
        <p>
          {{ state.quote }}
        </p>

        <cite> {{ state.author }} </cite>
      </blockquote>
      <blockquote class="quote-card">
        当前标签URL: {{ currentTabUrl }}
      </blockquote>
    </div>
  </template>
  <script>
  export default {
    data() {
      return {
        state: {
          quote: "",
          author: "",
        },
        currentTabUrl: "加载中..."
      };
    },
    async created() {
      // 获取随机名言逻辑不变
      try {
        const response = await fetch("https://zenquotes.io/api/random");
        const data = await response.json();

        if (Array.isArray(data) && data.length > 0) {
          this.state.quote = data[0].q;
          this.state.author = data[0].a;
        } else {
          this.state.quote = "获取名言失败";
        }
      } catch (error) {
        console.error(error);
        this.state.quote = "获取名言时发生错误";
      }

      // 向后台请求当前标签URL
      chrome.runtime.sendMessage({ type: "GET_CURRENT_TAB_URL" }, (response) => {
        this.currentTabUrl = response.url;
      });
    },
  };
  </script>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 23:00:42