一、说明

extensions 是由不同的组件(这些组件都是为了同一个目的)构成的。这些组件包括如下几种:

  • background scripts(运行在后台的脚本)
  • content scripts(运行在页面的逻辑脚本)
  • options page (页面)
  • ui elements(UI 元素)
  • 各种逻辑文件

上面的这些组件取决于 extensions 的功能,不一定全部都要拥有

extensions 使用 web 的开发技术区构建:HTML / CSS / JavaScript

二、创建 manifest.json

extension 必须依赖 manifest.json 开始:

{
    "name": "Getting Started Example",
    "version": "1.0",
    "description": "Build an Extension!",
    "manifest_version": 2
  }

想要在 chrome 上预览开发的扩展程序,只需要打开 manifest.json 存在的目录即可,具体方法可见:http://ptbird.cn/chrome-extensions-hello-world.html#menu_index_5

1.jpg

如果没有执行 logo,chrome 会为你生成一个默认的 logo,就是上面的 G

三、增加指令 background scripts

虽然已经安装了扩展程序,不过它没有任何的指令。我们可以通过创建 background.js 文件然后放在扩展程序的目录中来运行这个 background.js

background scripts 和其他的 component 必须在 mainifest.json 中说明,注册 background script 会告诉扩展程序需要引用那个文件,以及这个文件的行为方式。

{
    "name": "Getting Started Example",
    "version": "1.0",
    "description": "Build an Extension!",
    "background": {
      "scripts": ["background.js"],
      "persistent": false
    },
    "manifest_version": 2
  }

现在我们的扩展程序已经知道包含一个非持久性的后台脚本,(注意 persistent: false 的配置选项),扩展程序会扫描已经注册的脚本文件(比如 background.js)并且查找它需要坚挺的重要的事件。

我们的扩展程序一旦安装,就需要来自持久变量的信息,首先会在后台脚本中包含 runtime.onInstalled 的侦听事件。在 onInstalled 事件监听里面,扩展程序使用存储 API 设置了一个 value,然后能够允许多个扩展程序的 component 去访问或者 update。

background.js 代码如下:

chrome.runtime.onInstalled.addEventListener(() => {
    chrome.storage.sync.set({color: 'red'}, () => {
        console.log('color is red');
    });
});

上面的代码中,使用了 storage 权限,chrome 扩展开发中,涉及到 API 的使用,必须要在 manifest.json 的 permissions字段中注册才能使用。

{
    "name": "Getting Started Example",
    "version": "1.0",
    "description": "Build an Extension!",
    "permissions": ["storage"],
    "background": {
      "scripts": ["background.js"],
      "persistent": false
    },
    "manifest_version": 2
  }

上面的工作做完了之后,可以回到 chrome 的扩展页,然后重新加载扩展程序,这时候会出来一个【查看视图 背景页】

2.jpg

点击【查看视图】就会有 console 结果:

3.jpg

四、UI 用户界面

Chrome 的扩展程序拥有多种形式的用户界面,最简单的自然是 popup 类型,这里创建一个 popup.html 的页面,通过 button 来修改背景色。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        button {
          height: 30px;
          width: 30px;
          outline: none;
        }
      </style>
</head>
<body>
    <button id="changeColor"></button>
</body>
</html>

和 background script 一样,页面也需要在 manifest.json 中配置指定相关的文件:

{
    "name": "Getting Started Example",
    "version": "1.0",
    "description": "Build an Extension!",
    "permissions": ["storage"],
    "background": {
      "scripts": ["background.js"],
      "persistent": false
    },
    "page_action": {
        "default_popup": "popup.html"
    },
    "manifest_version": 2
  }

page_action 这个字段除了指定弹出页面地址外,还可以指定 default_icon,也就是扩展程序的 icon,可以指定不同分辨率的大小,配置是个对象,如果是字符串,则就使用一个 icon.比如下面的配置:

{
    "name": "Getting Started Example",
    "version": "1.0",
    "description": "Build an Extension!",
    "permissions": ["storage"],
    "background": {
      "scripts": ["background.js"],
      "persistent": false
    },
    "page_action": {
        "default_popup": "popup.html",
        "default_icon": {
            "16": "images/get_started16.png",
            "32": "images/get_started32.png",
            "48": "images/get_started48.png",
            "128": "images/get_started128.png"
        }
    },
    "manifest_version": 2
  }

除了上面配置的控制栏上的图标外,还可以配置在扩展程序管理页、权限警告的提示以及 favicon 上的图标,可以在 icons 字段中配置:

{
    "name": "Getting Started Example",
    "version": "1.0",
    "description": "Build an Extension!",
    "permissions": ["storage"],
    "background": {
      "scripts": ["background.js"],
      "persistent": false
    },
    "page_action": {
        "default_popup": "popup.html",
        "default_icon": {
            "16": "images/get_started16.png",
            "32": "images/get_started32.png",
            "48": "images/get_started48.png",
            "128": "images/get_started128.png"
        }
    },
    "icons": {
        "16": "images/get_started16.png",
        "32": "images/get_started32.png",
        "48": "images/get_started48.png",
        "128": "images/get_started128.png"
    },
    "manifest_version": 2
  }

4.jpg

可以看到,配置完 icons 之后,可以发现在管理页上我们已经有一个 logo 了。

如果子阿哥时候重新加载扩展程序,它会有一个灰色图标,不过没有任何功能上的差异。因为在 manifest 中声明了page_action, 所以扩展程序可以告诉浏览器用户什么时候能够和 popup.html 进行交互。

可以使用 runtime.inInstalled 监听器中的 declarativeContent API 将生命的规则添加到 background script。

chrome.runtime.onInstalled.addListener(() => {
    chrome.storage.sync.set({ color: 'red' }, () => {
        console.log('color is red');
    });
});

chrome.declarativeContent.onPageChanged.removeRules(undefined, () => {
    chrome.declarativeContent.onPageChanged.addRules([{
        conditions: [new chrome.declarativeContent.PageStateMatcher({
            pageUrl: { hostEquals: 'ptbird.cn' }
        })
        ],
        actions: [new chrome.declarativeContent.ShowPageAction()]
    }]);
});

同样的, declarativeContent 也是需要权限声明的:

 {
    "name": "Getting Started Example",
  ...
    "permissions": ["declarativeContent", "storage"],
  ...
  }

上面代码的衣衣是,当用户浏览的网页中包含 ptbird.cn 这个 host 的时候,我们的扩展程序会被激活,同时,这个时候点击按钮,就会显示我们的 popup.html 的页面内容:

5.jpg

现在我们已经有了 UI 了,那我们接下来需要给这个 UI 的 button 增加一些颜色,创建一个 popup.js 文件:

const changeColor = document.getElementById('changeColor');

chrome.storage.sync.get('color', (data) => {
    changeColor.style.backgroundColor = data.color;
    changeColor.setAttribute('value', data.color);
})

然后在 popup.html 中引入 js 文件:

<body>
    <button id="changeColor">按钮</button>
</body>
<script src='popup.js'></script>
</html>

刷新 extension 即可变成红色按钮

6.jpg

五、交互逻辑

目前为止我们的扩展程序已经知道弹出窗口应该可以给 ptbird.cn 的用户使用并显示彩色按钮,但是需要逻辑以进行进一步的用户交互,更新 popup.js 的代码如下:

const changeColor = document.getElementById('changeColor');

chrome.storage.sync.get('color', (data) => {
    changeColor.style.backgroundColor = data.color;
    changeColor.innerText = data.color;
});

changeColor.onclick = (element) => {
    const color = element.innerText;
    console.log(res);
    chrome.tabs.query({ active: true, currentWindow: truse }, (tabs) => {
        chrome.tabs.executeScript(
            tabs[0].id,
            { code: `document.body.style.backgroundColor = "${color}"` }
        )
    })
}

上面代码中我们通过 xxx.onclick 的方式吧脚本注入到了 html 中,实际上这就是一开始提到的 inject scripts
使用编程注入允许用户调用的内容脚本,而不是将不需要的代码自动插入到网页中。

上面代码中使用了 activeTab 权限,同样需要在 mainifest 中声明:

{
    "name": "Getting Started Example",
  ...
    "permissions": ["activeTab", "declarativeContent", "storage"],
  ...
  }

五、提供用户选项

目前,扩展程序仅允许用户将背景更改为绿色。通过包含选项页面,用户可以更好地控制扩展程序的功能,进一步自定义其浏览体验。

我们创建一个 options.html

 <!DOCTYPE html>
  <html>
    <head>
      <style>
        button {
          height: 30px;
          width: 30px;
          outline: none;
          margin: 10px;
        }
      </style>
    </head>
    <body>
      <div id="buttonDiv">
      </div>
      <div>
        <p>Choose a different background color!</p>
      </div>
    </body>
    <script src="options.js"></script>
  </html>

然后在 manifest 中配置 options_page 选项:

"options_page": "options.html",

然后在扩展程序管理页面,点击【详细信息】,然后滚动到下面会发现一个【扩展程序选项】的链接,虽然现在是个空的:

7.jpg

8.jpg

最后一步是添加选项逻辑。使用以下代码在扩展目录中创建名为 options.js的文件:

const page = document.getElementById('buttonDiv');

const kButtonColors = ['#3aa757', '#e8453c', '#f9bb2d', '#4688f1'];

function constructOptions(kButtonColors) {
    for (let item of kButtonColors) {
      let button = document.createElement('button');
      button.style.backgroundColor = item;
      button.addEventListener('click', function() {
        chrome.storage.sync.set({color: item}, function() {
          console.log('color is ' + item);
        })
      });
      page.appendChild(button);
    }
  }
  constructOptions(kButtonColors);

提供四种颜色选项,然后使用onclick事件侦听器在选项页面上生成为按钮。

当用户单击按钮时,它会更新扩展程序的全局存储中的颜色值。由于所有扩展文件都从全局存储中提取颜色信息,因此不需要更新其他值。