一次简单的chrome插件开发尝试——EditWeb

1,453 阅读4分钟

空闲之余,了解了一下chrome插件的开发,摸索着开发了几个简单的小工具。

EditWeb

本次先介绍第一个chrome插件——EditWeb,它是一款功能非常单一的插件,非常适合初学者首次尝试,它唯一的功能就是可以自由编辑任何网页,实现也非常简单,这是项目地址

开始

搭建项目

我们先创建一个项目文件夹EditWeb,在文件夹中新增manifest.json文件,它是chrome插件的必要描述文件,通过它浏览器才能识别出这是它的扩展。

配置manifest.json

{
    "name": "EditWeb",
    "description": "自由编辑网页元素",
    "version": "0.0.1",
    // manifest.json版本 
    "manifest_version": 2,
    // 图标
    "icons": {
        "16": "images/logo.png",
        "48": "images/logo.png",
        "128": "images/logo.png"
    },
    // 弹出页配置
    "browser_action": {
        // 默认图标
        "default_icon": "images/logo.png",
        // 类似html标签的title,鼠标放到图标上展示的内容
        "default_title": "EditWeb",
        // 点击图标后弹出的页面
        "default_popup": "index.html"
    },
    "background": {
        "scripts": [
            "js/background.js"
        ],
        // true表示一直运行
        "parsistent": false
    },
    "content_scripts": [
        {
            // 指定那些网页可使用脚本,<all_urls>是所有网页
            "matches": [
                "<all_urls>"
            ],
            "js": [
                "js/content-script.js"
            ],
            // 脚本添加时机
            // document_start:在页面之前插入 js 代码。
            // document_end:在页面末尾插入js代码。 
            // document_idle : 页面空闲时加载。
            "run_at": "document_idle"
        }
    ],
    // 权限
    "permissions": [
        // 右键菜单
        "contextMenus",
        // 标签
        "tabs",
        // 通知
        "notifications",
        // web请求
        "webRequest",
        "webRequestBlocking",
        // 本地存储
        "storage",
        "cookies",
        // 可以通过executeScript或者insertCSS访问的网站
        "http://*/*",
        "https://*/*"
    ]
}

我们能看到配置中有个弹出页配置browser_action,什么是弹出页呢?就是我们点击chrome右上角插件图标弹出的窗口。

image.png

配置中的background又是什么呢?通常把需要长时间运行的、全局的代码放在background里面,它运行在一个独立运行环境,其实也可以说是运行在“后台”的一个页面,它是与当前浏览页面无关的。

content_scripts是可以操作dom的,它是运行在Web页面的上下文的js文件,可以操作(读取并修改)浏览器当前访问的Web页面的内容。

permissions可以控制扩展拥有的权限。

index.html

EditWeb文件夹下建立index.html文件,它是弹出页的html。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./css/index.css">
    <script src="./js/index.js"></script>
</head>
<body>
    <section class="title">
        <div>编辑模式</div>
    </section>
    <section class="footer">
        <div>
            <button id="openBtn">开启</button>
            <button id="stopBtn">关闭</button>
        </div>
    </section>
</body>
</html>

然后在建立css文件夹,创建index.css文件,它是弹出页的样式文件。

* {
    margin: 0;
    padding: 0;
  }
  body {
    width: 334px;
  }
  .title {
    font-size: 16px;
    font-weight: bold;
    width: 100%;
    padding: 20px;
    padding-bottom: 10px;
  }
  .content {
    width: 100%;
    font-size: 14px;
  }
  .content form {
    padding: 30px;
    margin: -20px 0px;
  }
  .content form .tips {
    display: flex;
    align-items: center;
  }
  .content form .tips-div {
    font-size: 12px;
    color: #ccc;
    margin-top: 10px;
  }
  .content form .tips-input {
    position: relative;
  }
  .content form input {
    outline-style: none;
    border: 1px solid #ccc;
    border-radius: 3px;
    padding: 6px;
    width: 200px;
    font-family: 'Microsoft soft';
  }
  .content form input:focus {
    border-color: #66afe9;
    outline: 0;
    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
  }
  .footer {
    padding: 20px;
    padding-top: 10px;
    text-align: right;
    box-sizing: border-box;
  }
  .footer button {
    display: inline-flex;
    justify-content: center;
    align-items: center;
    line-height: 1;
    height: 32px;
    white-space: nowrap;
    cursor: pointer;
    color: #fff;
    text-align: center;
    box-sizing: border-box;
    outline: none;
    transition: 0.1s;
    font-weight: 500;
    user-select: none;
    vertical-align: middle;
    -webkit-appearance: none;
    background-color: #409eff;
    border: 1px solid #4c4d4f;
    border-color: #409eff;
    font-size: 14px;
    border-radius: 20px;
    padding: 8px 15px;
  }
  .footer button:hover {
    color: #fff;
    border-color: #3375b9;
    background-color: #3375b9;
    outline: none;
  }
  .footer button:active {
    color: #fff;
    border-color: #66b1ff;
    background-color: #66b1ff;
    outline: none;
  }

在js文件夹下创建相关脚本文件background.js,content-script.jsindex.js

最终项目结构如下图:

image.png

此时我们在chrome扩展程序页点击加载已解压的扩展程序,选择该项目文件夹,即可看到插件已安装到我们的chrome上。

image.png

将插件固定到浏览器右上角后,点击小图标,你就能看到刚写的弹出页。

image.png

此时,我们的插件就有了一副外壳,接下来就是填充他的血肉。

index.js

我们需要在这个脚本中获取弹出页的按钮,并且绑定点击事件。当点击开启或者关闭按钮时需要发送相应消息给插件后台。此处的消息我传的是一个带有designMode属性对象,用来控制document.desginMode来控制页面的设计模式,从而达到控制是否可编辑的效果。

window.onload = () => {
    const openBtn = document.getElementById('openBtn')
    const stopBtn = document.getElementById('stopBtn')
    openBtn.onclick = function() {
        chrome.runtime.sendMessage({designMode: 'on'})
    }
    stopBtn.onclick = function() {
        chrome.runtime.sendMessage({designMode: 'off'})
    }
}

background.js

background.js中需要监听index界面传过来的消息,并且把消息传递给content-script。同时在background中我们创建右键菜单,使打开编辑模式更加方便。

const sendData = (data) => {
  chrome.tabs.query(
    {
      active: true,
      currentWindow: true,
    },
    (tabs) => {
      chrome.tabs.sendMessage(tabs[0].id, data, (res) => {});
    }
  );
};

const contextMenus = {
  id: "openDesignMode",
  title: "开启编辑模式",
  type: "normal",
  contexts: ["page"],
  onclick: function () {
    sendData({ designMode: "on" });
  },
};

chrome.contextMenus.create(contextMenus);

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  sendData(message);
  sendResponse('ok')
});

content-scripts.js

最后在content-scripts中监听background传过来的消息,根据消息控制页面的document.designMode值。

结束

到此一个简单的chrome插件就开发完成了,由于是第一次开发插件,可能存在某些bug,请多多包含。