前言
建议先去看源码,再来看文章, 仅有前端代码, 后端接口没写,别问问就是懒……
因为群主乐于分享,有时候把网页添加到书签之后,系统重装啊 浏览器卸载呐……各种杂七杂八的问题,这样导致书签全没了(主要是懒)
索性就写个浏览器插件,当看到好文章的时候也可以保存至服务器,也方便分享给团队成员。
目的明确 浏览器插件, 在查相关资料得时候想起来以前看过一篇政采云的浏览器插件文章。
好家伙天助我也……政采云给大致方案,这个大兄弟直接把代码写完了……
不过这个大兄弟的代码是vue2的,所以咱们就用vue3 + typescript 实现一个自己……
项目配置
项目创建这里就略过了……
配置项目
项目创建完成了,咱们就要去装点npm包来开发了。
copy-webpack-plugin 拷贝文件
@types/chrome 谷歌浏览器类型
-
修改
tsconfig.js…… "types": [ "webpack-env" // 添加 chrome 后面要用到。 "chrome" ], …… -
创建了
vue.config.js(可以先把代码注释一下,因为现在还用不到)const CopyWebpackPlugin = require("copy-webpack-plugin"); const path = require("path"); module.exports = { configureWebpack: { plugins: [ new CopyWebpackPlugin({ patterns: [ { from: path.resolve("src/plugins/plugin-chrome.js"), to: path.resolve("dist/js") } ] }) ] } }; -
在public下创建
manifest.json{ "manifest_version": 2, "name": "galaxy-browser-extends", "homepage_url": "http://localhost:8080/", "description": "用于分享的浏览器插件", "permissions": ["<all_urls>", "*://*/*", "notifications", "webRequest"], "icons": { "16": "icons/16.png", "48": "icons/48.png", "128": "icons/128.png" }, "browser_action": { "default_popup": "popup.html", "default_title": "galaxy-browser-extends", "default_icon": { "19": "icons/19.png", "38": "icons/38.png" } }, "version": "0.1.0", "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'" }public 文件夹下创建icon, 再放入几张png。
-
修改下package.json 中的server 启动命令,方便于我们开发。
"serve": "vue-cli-service build --mode development --watch"
那么我们执行下 yarn serve, 安装插件。
使用插件
访问 chrome://extensions/, 打开开发者模式,点击 加载已解压的扩展程序, 选择项目目录下dist。不出问题的话可以看到插件加载成功了。
没啥问题能用……
manifest.json
在开始写功能之前我们先了解下一些前置知识。
每一个扩展、可安装的WebApp、皮肤,都有一个JSON格式的manifest文件,叫 manifest.json,里面提供了重要的信息。
{
"manifest_version": 2,
"name": "galaxy-browser-extends",
"homepage_url": "http://localhost:8080/",
"description": "用于分享的浏览器插件",
"permissions": ["<all_urls>", "*://*/*", "notifications", "webRequest"],
"icons": {
"16": "icons/16.png",
"48": "icons/48.png",
"128": "icons/128.png"
},
"browser_action": {
"default_popup": "popup.html",
"default_title": "galaxy-browser-extends",
"default_icon": {
"19": "icons/19.png",
"38": "icons/38.png"
}
},
"version": "0.1.0",
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
}
permissions:插件用到的浏览器的权限. MDN 插件API概览
icons: 图标 16px 48px 128px
browser_action: browser actions 可以在浏览器工具条的地址栏右边增加一个图标。 详细介绍
version: 插件版本
content_security_policy: 因为我们是用webpack打包的,所以要运行eval MDN
交互
我们主要的功能的功能就是获取到web页面的 title, url, description
那么我们要怎么才能拿到这些信息呢?
首先我们要获取到当前web页面的tabId, 并向这个页面注入js。注入了js,我们的插件还是没有办法直接跟当前的web 页面交互,还需要一步就是通过Message 传递消息。 消息传递Message
/**
* 获取当前页得tabid
* @returns
*/
export const ChromTabsQuery = (): Promise<number | any> => {
return new Promise((resolve, reject) => {
chrome.tabs.query(
{
active: true,
currentWindow: true
},
(tabs: Array<chrome.tabs.Tab>): void => {
tabs.length ? resolve(tabs[0].id) : reject(null);
}
);
});
};
/**
* 向浏览器注入脚本
* @param tabId
* @param path
* @returns
*/
export const ChromeTabsExecuteScript = (tabId: number, path: string) => {
return new Promise(resolve => {
chrome.tabs.executeScript(tabId, { file: path }, response => {
resolve(response);
});
});
};
/**
* 向浏览器发送Message
* @param tabId
* @param message
* @returns
*/
export const ChromeTabsSendMessage = (
tabId: number,
message: {}
): Promise<{
title: string;
link: string;
description: string;
}> => {
return new Promise(resolve => {
chrome.tabs.sendMessage(tabId, message, response => resolve(response));
});
};
要被注入的js
/* eslint-disable no-undef */
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message === "GET_TOPIC_INFO") {
// 获取 title
const title = document.getElementsByTagName("title")[0].textContent;
const descriptionEl = document.querySelectorAll("meta[name=description]")[0];
// 获取 描述
const description = descriptionEl ? descriptionEl.getAttribute("content") : title;
// 发送数据
sendResponse({
title: title.trim(),
link: location.href,
description: description.trim()
});
}
});
当我们想要获取Web页面信息的时候, 先获取到 tabId, 通过 tabId给相应的Web注入脚本。我们发送一条Message告诉脚本,脚本也会返回一条Message 给我们。
const tabId = await ChromTabsQuery();
const status = await ChromeTabsExecuteScript(tabId, "./js/plugin-chrome.js");
if (status) {
const result = await ChromeTabsSendMessage(tabId, {
message: "GET_TOPIC_INFO"
});
const { title, description, link } = result;
formData.title = title;
formData.description = description;
formData.link = link;
}
完结
可能讲的比较快,一些细节没有讲到。浏览器插件这块东西真的是非常多,而已很多资料都是英文的。中文的资料真的不是太多,主要是写浏览器插件的人相对较少。