如何开发谷歌扩展

前言

扩展(Extension),指的是通过调用 Chrome 提供的 Chrome API 来扩展浏览器功能的一种组件,工作在浏览器层面,使用 HTML + Javascript 语言开发[*]。比如著名的 Adblock plus。

下面我会以一个简单的 demo 来讲,该 demo 是一个简单翻译扩展,输入要翻译内容后把翻译结果输出到页面上。

一、目录结构

demo 主要目录结构如下:

|   background.js           // 后台脚本
|   index.html              // 浏览器点击本扩展时弹出的页面
|   manifest.json           // [重点] 扩展的配置文件,类似于 package.json
|
+---css                     // css 文件
|       all.css
|       style.css
|
+---img                     // 图片文件
|       favicon.ico
|       ico-logo.png
|       ico.png
|
\---js                      // js 文件
        translate.js        // 翻译脚本
        youdao.js           // 有道翻译页面脚本

二、配置 manifest.json

manifest.json 是扩展的配置文件,可以在里面配置在那个页面使用哪个 js 文件,以及一些其他配置

在 2021 年 9 月 23 日 发布下图时间线全力推 manifest V3

下面可以看看大概结构

{
  "name": "插件名",
  "author": "插件作者",
  "manifest_version": 3,
  "version": "1.0.0",
  "description": "插件描述",
  // 插件图标
  "icons": {
    "16": "img/ico-logo.png",
    "48": "img/ico-logo.png",
    "128": "img/ico-logo.png"
  },
  // 『重点』action配置项主要用于点击图标弹出框,对于弹出框接受的是html文件
  "action": {
    "default_popup": "index.html",
    "default_title": "鼠标移上去时的提示",
    "default_icon": {
      "16": "img/ico-logo.png",
      "48": "img/ico-logo.png",
      "128": "img/ico-logo.png"
    }
  },
  // 允许使用扩展的域名
  "host_permissions": ["http://*/", "https://*/"],
  // 『包含已知字符串列表中的项目 【只需一次弹框要求允许】
  "permissions": [
    "contextMenus",
    "tabs",
    "webRequest",
    "storage",
    "notifications",
    "activeTab"
  ],
  // 『与常规类似permissions,但由扩展的用户在运行时授予,而不是提前授予【安全】
  "background": {
    "service_worker": "background.js"
  },
  // 『重点』应用于所有页面上下文的js
  "content_scripts": [
    {
      // 匹配的页面
      "matches": ["https://fanyi.youdao.com/*"],
      "js": [
        // 这个 js 将会在 https://fanyi.youdao.com/* 页面中运行
        "js/youdao.js"
      ]
    }
  ]
}

三、各个文件代码

index.html

<!DOCTYPE html>

<html lang="zh">
  <head>
    <meta charset="UTF-8" />
    <title></title>
    <link rel="stylesheet" type="text/css" href="./css/style.css" />
  </head>

  <body>
    <div class="container">
      <div class="input-box">
        <input
          type="text"
          id="input"
          placeholder="请输入你要翻译的内容"
          autofocus
        />
        <button id="btn">翻译</button>
      </div>
      <div class="all">
        <a id="all">翻译此页面</a>
      </div>
      <div class="result-box">
        <div class="result-content" id="result"></div>
      </div>
    </div>
  </body>
  <footer class="footer">
    <div id="autoOption">
      本翻译由&nbsp;<a href="https://fanyi.youdao.com/" target="_blank"
        >有道翻译</a
      >&nbsp;提供
    </div>
  </footer>

  <script src="./js/translate.js"></script>
</html>

效果如下:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

translate.js

const btn = document.getElementById("btn");
const text = document.getElementById("input");
const result = document.getElementById("result");
const all = document.getElementById("all");

/**
 * 翻译
 * @param {string} text 要翻译的内容
 */
const translate = (text) => {
  request(text, (res) => {
    let arr = res?.translateResult[0] || [];
    let str = "";
    arr.map((v) => {
      str += v.tgt;
    });
    result.textContent = str;
  });
};

/**
 * 请求
 * @param {string} str 要翻译的内容
 * @param {function} callback 回调函数
 * @returns
 */
const request = (str, callback) => {
  let xhr = new XMLHttpRequest();
  xhr.open(
    "GET",
    `https://fanyi.youdao.com/translate?&doctype=json&type=AUTO&i=${str}`
  );
  xhr.send();
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
      callback(JSON.parse(xhr.responseText));
    }
  };
};

/**
 * 翻译按钮点击事件
 * @returns
 */
btn.addEventListener("click", () => {
  try {
    translate(text.value);
  } catch (err) {
    result.textContent = "翻译失败" + err;
  }
});

/**
 * TODO:翻译整页按钮点击事件
 * @returns
 */
all.addEventListener("click", () => {
  try {
    // TODO: 翻译整页
    // chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
    //   chrome.tabs.sendMessage(
    //     tabs[0].id,
    //     { type: "searchAllGoogle" },
    //     function (response) {
    //       console.log("接收到消息", response);
    //       if (response) {
    //         result.textContent = response.text;
    //       }
    //     }
    //   );
    // });
  } catch (err) {
    console.log("翻译整页失败", err);
  }
});

youdao.js

// 获取有道翻译页上的元素
const input = document.getElementById('inputOriginal');
const btn = document.getElementById('transMachine');

// 如果 url 携带有参数,那么解码并获取 url 参数
const getUrlParam = (name) => {
  var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
  var r = window.location.search.substr(1).match(reg);
  if (r != null) return decodeURI(r[2]); return null;
}

// 自动点击翻译按钮
if (getUrlParam('i')) {
  input.value = getUrlParam('i');
  btn.click();
} else {
  input.focus();
}

后面可以点击测试: https://fanyi.youdao.com/index.html#/?i=杀杀杀

background.js,这个虽然有,但还没有写任何东西,后面会用到

// TODO: 监听来自content-script的消息
// TODO: 翻译整页是可能需要用到发送消息给content-script

// 监听来自content-script的消息
// chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
//   console.log("收到来自content-script的消息:");
//   console.log(request, sender, sendResponse);
//   sendResponse("我是后台,我已收到你的消息:" + JSON.stringify(request));
// });

// 发送消息给content-script
// chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
//   // 通过chrome.tabs.sendMessage给content-script发消息
//   chrome.tabs.sendMessage(tabId, { greeting: "hello" }, function (response) {
//     console.log("收到来自content-script的回复:" + response);
//   });
// });

四、打包

打包的时候需要注意,如果你的扩展需要用到第三方库,那么需要在 manifest.json 中的 content_scripts 中的 js 中引入,否则打包后会报错

打开谷歌扩展页,上面有几个选项 [加载已解压的扩展程序]、[打包扩展程序]、[更新],可以选择[打包扩展程序],选择源码路径,再点击确定就会生成一个 crx 文件,这个文件就是我们的扩展了。

五、运行效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

六、源码地址

Gitee
Github

  • 17
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值