从0到1设计开发Chrome插件

·  阅读 1919

TNTWeb - 全称腾讯新闻中台前端团队,组内小伙伴在Web前端、NodeJS开发、UI设计、移动APP等大前端领域都有所实践和积累。

目前团队主要支持腾讯新闻各业务的前端开发,业务开发之余也积累沉淀了一些前端基础设施,赋能业务提效和产品创新。

团队倡导开源共建,拥有各种技术大牛,团队Github地址:github.com/tnfe

本文作者冷叶 项目地址: github.com/freezeYe/wu…

image.png

一、场景

之前一直在公司业务上做H5开发,发现项目的繁琐点不在某一个具体的业务逻辑,而是无数个已经上线或者下线亦或是反反复复上上下下的AB测。对于前端开发来说,其中一个低效的点便在于如何去管理众多的链接,因为每一个参数对应了一个命中实验。举个 ,首先是域名我们有四套(本地、测试、预发布、线上)环境,然后是页面路径总共有两级页每一级对应了无数个文章链接,而每个文章链接又对应了多个AB测参数。 Chrome上自带了书签功能,但一个问题是书签只能做单链接存储,在实际开发中我们的域名、路径和参数其实都拥有自身的含义,比如

https://view.kuaikan.com/a2/20171129V077ODs0?W2VIDEO=1&pluginab=1&tint=1&W2VIDEOLAB=0
复制代码

这样的一个链接,他表达了怎样的实际意义呢?如下图所示:

其实这是一个排列组合的问题,我们期望的是可以在链接的每个维度上做拆分,并通过灵活重组生成新的链接并快捷访问。在这个基础上就引入了本文要介绍的“悟空记录”插件,这样我们就可以在最大程度上复用单个链接的每个字段。

wecom-temp-0eaa1ff42eddeff9091392fea68766a3.png

二、悟空记录

在Chrome网上商店搜索“悟空插件”点击“添加至Chrome”,我们就可以在浏览器右上角看到这样的icon标签 这就是我们的悟空插件应用。

插件核心分为三部分,第一部分是保存页。在下图我们能看到顶部显示了当前活动tab的url链接,下面三个输入框分别对应了我们对该链接域名、路径、参数的独立定义,填写上对应的值后点击保存我们会看到输出结果。

wecom-temp-fd3e19478f7eb42cf610ab39ae0d6727.png

第二部分是访问列表页,点击“访问”我们能看到之前已经保存的原信息,这里我又单独添加了一条线上环境的域名记录,所有链接的重复字段值采用了复写机制。

wecom-temp-4d188a2f16777fe3dba498487ac2c813.png

在上图中点选择任意组合,点击打开后我们就可以看到新的重组链接被打开了。

image.png 第三部分是信息管理页面,我们点击弹出页中的“扩展程序选项”,就能看到先前记录的所有信息。目前只支持了删除功能,后续计划在页面上提供组合链接直接生成二维码能力来优化移动端开发体验。

image.png

三、Chrome插件开发

深入了解插件开发前先我们先来理清一些基本的概念。首先是background.js 定义了插件注册安装到浏览器时自动执行的一些操作,比如根据当前环境来判断该插件是否启用(icon高亮/置灰)。popup.html就是我们在点击插件时的弹窗,popup.js是拥有其执行上下问的脚本文件。contentscript.js 注入了我们打开一个网页时的context,它与前述的脚本环境隔离,通过postMessage的形式来互相通信。下图少了一部分options.html和options.js,这是选项页面和他自身的执行脚本,在插件开发中一般用来做独立的管理后台,在下文介绍本插件的开发中会描述到。

wecom-temp-7d0f25594bdaf05bb2f7a6c82e1b7820.png

有了这些概念后我们会想,chrome是如何去识别每个内容呢?它其实是通过manifest.json的json文件,里面描述了对应的资源路径,以悟空插件来看。

name:当我们鼠标放到插件icon上显示的组件名; version:发布到chrome插件商店对应版本号; description:显示在插件上的简短介绍; browser_action:指定了浏览器安装插件后显示的icon和点击时弹出的页面; icons:显示在商城、设置等地方所对应的不同尺寸icon; options_page:指定了我们的选项页; permissions:指定了对该插件的chrome api授权,为了防止xss等诸如攻击。 这里我们缺少的其余两个重要选项是background,因为该插件不存在需要后台运行的js,还有一个是page_action对应了browser_action,区别在于browser_action作用于所有页面,通过page_action配置的popup.html需要手动调用chrome的api激活。

{
  "name": "Domain and Parameter combination",
  "version": "1.0",
  "manifest_version": 2,
  "author": "freezeYe",
  "description": "Separate Domains and Parameters and Regroup",
  "permissions": ["storage", "declarativeContent", "activeTab", "tabs"],
  "browser_action": {
    "default_popup": "src/html/popup.html",
    "default_icon": "images/nokia_suite_mirror.png"
  },
  "icons": {
    "16": "images/nokia_suite_mirror.png",
    "32": "images/nokia_suite_mirror.png",
    "48": "images/nokia_suite_mirror.png",
    "128": "images/nokia_suite_mirror.png"
  },
  "options_page": "src/html/options.html"
}
复制代码

接下来在对应路径下创建相应的文件,我们就能通过扩展程序的“加载已解压的扩展程序”来将项目打包到我们自身的浏览器上来同步开发。

image.png

开发框架可以按照个人喜好配置,只要保证最终打包成浏览器兼容的JS即可。这里放一段该项目选项页的原生JS代码,由于项目比较小巧并没有再使用其他的库和框架,仅供参考。

const hostContainer = document.getElementById('host');
const pathContainer = document.getElementById('path');
const queryContainer = document.getElementById('query');

// storage 缓存键
const CACHED_KEY = '__wukongCache';
function init() {
  chrome.storage.sync.get([CACHED_KEY], (result) => {
    const { __wukongCache = {} } = result;
    const { hostMap, pathMap, queryMap } = __wukongCache;
    blockGen(hostMap, hostContainer, 'hostMap');
    blockGen(pathMap, pathContainer, 'pathMap');
    blockGen(queryMap, queryContainer, 'queryMap');
  });
}

// 根据数据生成对应区块
function blockGen(data, container, type) {
  let tbody = '';
  let thead = '<thead><tr><th>名称</th><th>值</th><th>操作</th></tr></thead>';
  Object.keys(data).forEach((key) => {
    tbody += `<tr>
      <td>${data[key]}</td>
      <td>${key}</td>
      <td class="delete" data-key=${key} >删除</td>
    </tr>`;
  });
  tbody = `<tbody>${tbody}</tbody>`;
  tbody = str2cell(tbody);
  thead = str2cell(thead);
  tbody.addEventListener('click', (e) => {
    if (e.target.innerText === '删除') {
      const r = confirm('确认删除该条记录?');
      if (r) deleteItem(e, type);
    }
  });
  // eslint-disable-next-line no-param-reassign
  container.innerHTML = '';
  container.append(thead);
  container.append(tbody);
}

// 字符串转dom
function str2cell(str) {
  const table = document.createElement('table');
  table.innerHTML = str;
  return table.firstChild;
}

// 删除元素
function deleteItem(e, type) {
  const { target } = e;
  const deleteKey = target.dataset.key;
  chrome.storage.sync.get(['__wukongCache'], (result) => {
    const { __wukongCache = {} } = result;
    const { [type]: data } = __wukongCache;
    Reflect.deleteProperty(data, deleteKey);
    chrome.storage.sync.set({ [CACHED_KEY]: __wukongCache }, init);
  });
}

init();
复制代码

如何发布,当项目开发完成后打开Chrome网上应用商店,点击开发者信息中心按钮跳转。

新用户需要注册成为开发者,绑定信用卡/借记卡支付5美金。

image.png

注册成功后在首页点击“上传新内容”,将项目以manifest.json作为根路径的文件夹打包成.zip文件上传,最后在“商品详情”和“隐私权”等地方完善插件信息,直到“提交审核”按钮可点击后上传。

image.png

审核提交后我们就能在内容栏内看到我们的插件状态,当审核成功后我们就可以在Chrome商城内检索到我们的插件按照到浏览器啦,5美刀买不了吃亏买不了上当。

image.png

分类:
前端
分类:
前端