油猴腳本開發教程
前言
如何跟普通朋友介紹前端工程師是一個怎樣的職位? 我會毫不猶豫的給他的瀏覽器裝上 Tampermonkey,再裝一個去廣告插件 [1],他們肯定會覺得你很牛逼,然後再問問他們,有些時候想複製某度文檔,卻複製不了,再給他們裝一個 XX 文庫的選中複製插件 [2],瞬間成就感拉滿,前端工程師就是幹這個事的,筆者之前也寫了幾個油猴腳本,接下來我就分享下寫腳本的經驗,一起來看看吧。
什麼是油猴腳本
Tampermonkey[3] 是一款免費的瀏覽器擴展和最爲流行的用戶腳本管理器,它適用於 Chrome, Microsoft Edge, Safari, Opera Next, 和 Firefox。
「油猴腳本」是一段腳本代碼,通過它可以讓瀏覽器實現各種各樣的擴展功能,和瀏覽器擴展的作用類似。比如獲去鏈接重定向、微博頁面精簡、去廣告等,相當於給瀏覽器開了個掛,可以說是瀏覽器的輔助神器了!但瀏覽器擴展若要發佈到 chrome 擴展市場,需要支付 5 美元,但「油猴腳本」可以隨時隨地發佈,不需要支付任何費用費用。
新建腳本
在腳本管理控制檯,右上角的+
添加按鈕,新建一個腳本,默認會包含以下代碼:
新建腳本
最上面的註釋不能刪除,Tampermonkey 就通過註釋代碼來配置腳本字段的
-
@match
用來匹配注入腳本網址的 url 其中 * 代表一個或者多個任意字符若要匹配 baidu 域名下人任意網頁可以使用
*://*.baidu.com/*
;若要匹配任意網址,可以使用
*://*/*
-
@require
代表要注入的公用 JS 庫比如要使用 jquery,可以使用以下代碼
// @require https://code.jquery.com/jquery-2.1.4.min.js
// @require tampermonkey://vendor/jquery.js
// @require tampermonkey://vendor/jszip/jszip.js
CSDN 免登陸複製
比如 CSDN 中代碼塊複製必須要登錄後纔可以複製, 那麼我們就可以寫一個腳本,輸入以下代碼
// ==UserScript==
// @name CSDN 免登錄複製
// @version 0.1
// @description try to take over the world!
// @match *://*.csdn.net/*
// @require tampermonkey://vendor/jquery.js
// @grant none
// ==/UserScript==
(function() {
'use strict';
$("pre,code").css("user-select","auto");
})();
保存後,重新刷新瀏覽器,在右上角的擴展標誌中會向上一個1
, 說明有一個擴展作用於這個網頁,腳本注入成功。
CSDN 免登陸複製
其實就是一行代碼,CSDN 的默認代碼塊的樣式是 user-select: none;
,不能複製,改成 auto
後就可以複製了。
添加樣式
首先需要在最上面的註釋中開啓權限 @grant
GM_addStyle
,然後就可以使用內置的 GM_addStyle
方法了。
// ==UserScript==
// @grant GM_addStyle
// ==/UserScript==
GM_addStyle(`pre,code{user-select:auto !important}.signin{display: none !important;}`)
這樣也可以解決 CSDN 代碼塊不能複製的問題,順便將代碼塊後面的登錄後複製
按鈕隱藏;
當然我們也可以使用 JS 自己實現
const heads = document.querySelector('head');
const style = document.createElement('style');
style.setAttribute('type', 'text/css');
style.innerHTML = `pre,code{user-select:auto !important}.signin{display: none !important;}`;
heads.append(style);
網絡請求
一般前端腳本都是修改前端網頁內容,若複雜一點的腳本,可能會涉及到動態數據,比如我們在腳本中直接寫fetch
請求,這時瀏覽器肯定會阻止請求,因爲跨域了。
我們需要使用腳本的內置方法
// ==UserScript==
// @grant GM_xmlhttpRequest
// ==/UserScript==
GM_xmlhttpRequest({
headers: {
'content-type': 'application/json',
},
responseType: 'json',
url: 'https://api.juejin.cn/recommend_api/v1/article/recommend_cate_feed',
data: '{"id_type":2,"sort_type":200,"cate_id":"6809637767543259144","cursor":"0","limit":20}',
method: 'POST',
onreadystatechange: (res) => {
if (res.readyState === 4) {
console.log(res.response)
}
},
})
在最上面的註釋中開啓權限 @grant
GM_xmlhttpRequest
,然後就可以使用內置的 GM_xmlhttpRequest
方法了。
比如把接口換成有道翻譯的 api。通過 document.getSelection().toString();
獲取網頁中的選中文本,便可以實現一個劃詞翻譯油猴插件了。
劃詞翻譯
右鍵搜索
接下來我們將結合右鍵菜單和打開新窗口的內置函數,實現一個快捷搜索的功能, 同樣內置函數需要在最上面的註釋中加入權限,代碼如下:
// ==UserScript==
// @grant GM_registerMenuCommand
// @grant GM_openInTab
// ==/UserScript==
GM_registerMenuCommand("GitHub 搜索", function () {
const str = document.getSelection().toString();
if (str) {
GM_openInTab(`https://github.com/search?q=${str}`, { active: true });
}
});
GM_registerMenuCommand("NPM 搜索", function () {
const str = document.getSelection().toString();
if (str) {
GM_openInTab(`https://www.npmjs.com/search?q=${str}`, { active: true });
}
});
右鍵搜索
這樣就有了快捷菜單搜索的功能,只是操作掛着 3 級目錄下,操作有些不方便。
以上簡單介紹了腳本的開發以及一些簡單實現,但這個腳本我們只能在自己電腦使用,若想讓其他小夥伴也能夠使用,我們需要將腳本發佈到腳本腳本市場,供其他小夥伴下載。
腳本發佈
一個非常流行的腳本共享網站便是 greasyfork.org[4],有着非常豐富的腳本,並且支持多語言。
greasyfork 腳本發佈
註冊賬號後,點擊右上角的用戶名
,然後點擊控制檯中的發佈你編寫的腳本
,貼入你寫的腳本代碼,便可以發佈成功!將發佈後的鏈接發送個小夥伴,就可以讓他們安裝你寫的腳本了,你也可以在上面根據匹配域名搜索相關腳本,看大神們是如何來寫腳本的。
前端工程化
現代前端開發已經離不開前端框架,若直接使用原生 JS 讓我們寫複雜的功能,難免會讓我們崩潰,比如需要在 JS 中寫 CSS,一不小心寫錯就會讓整個腳本無法執行。所以我們可以使用 webpack 來構建一個工程化的項目。並且使用 Typescript 和 eslint ,讓我們的前端工程健全。
下面是 webpack.config.js
const webpack = require("webpack");
const fs = require("fs");
const path = require("path");
const config = {
entry: "./src/index.tsx",
output: {
clean: true,
iife: true,
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
},
devServer: {
static: {
directory: path.join(__dirname, "public"),
},
compress: true,
port: 9000,
},
// 腳本發佈後,會被舉報,不允許壓縮
optimization: {
minimize: false,
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: "babel-loader",
exclude: /node_modules/,
},
{
test: /\.css$/,
use: [
{
loader: "style-loader",
options: {},
},
{ loader: "css-loader" },
],
},
{
test: /\.ts(x)?$/,
loader: "ts-loader",
exclude: /node_modules/,
},
],
},
plugins: [new BannerPlugin()],
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
};
module.exports = config;
使用 style-loader
,在 webpack 打包後,會自動將 css 樣式通過 style 標籤插入到 head 中,這樣就做到了 css 和 js 分離。這裏有個問題,就是油猴腳本特有的代碼前置註釋 ==UserScript==
,在 webpack 打包後會被刪除,所以我們得自己實現一個插件,將這段註釋加回來。
const ConcatSource = require("webpack-sources").ConcatSource;
/**
* 添加前綴註釋
*/
class BannerPlugin {
apply(compiler) {
let banner = "";
const entryFile = compiler.options.entry.main.import[0];
const res = fs.readFileSync(entryFile, "utf-8");
const matched = res.match(
/(\/\/\s==UserScript==)(?<content>(\n.+)+)(\n\/\/\s==\/UserScript==)/
);
if (matched && matched.groups.content) {
banner =
"// ==UserScript==" + matched.groups.content + "\n// ==/UserScript==\n";
}
compiler.hooks.emit.tap("BannerPlugin", (compilation) => {
compilation.chunks.forEach((chunk) => {
// 最終生成的文件的集合
chunk.files.forEach((fileName) => {
compilation.assets[fileName] = new ConcatSource(
banner,
compilation.assets[fileName]
);
});
});
});
}
}
上述代碼通過正則匹配 ==UserScript==
之間的代碼,並且將匹配的內容合併到了最後的代碼 chunk
中。
CICD
若我們每次打包後的 JS 都需要手動拷貝到 greasyfork.org
未免有些麻煩,得意於 greasyfork.org
有個自動發佈的功能,我們可以配合 GitHub actions 來實現自動發佈。
在項目文件夾下建立 .github/workflows/build.yml
, 輸入以下代碼
name: GitHub Pages
on:
push:
branches:
- main
pull_request:
jobs:
deploy:
runs-on: ubuntu-20.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: "14"
- name: Get yarn cache
id: yarn-cache
run: echo "::set-output
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- run: yarn install
- run: yarn build
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
if: ${{ github.ref == 'refs/heads/main' }}
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
當我們把代碼提交到 Github ,就會自動觸發 workflow ,依次執行 yarn install
、yarn build
並且自動將 dist
目錄下的代碼自動部署到 GitHub pages。
接下來我們複製 pages 中的 raw 源文件地址
github 源文件地址
貼入複製的源文件地址
-
設置腳本同步爲自動
-
並且設置 webhook
webhook 配置
複製這裏對應的 webhook 地址和祕鑰
github 設置 webhook
在 GitHub 項目地址中添加 webhook
這樣只要我們一旦提交代碼, greasyfork.org 中的腳本便會自動更新最新版本。
以上所有配置我整理在 tampermonkey-starter[5] 中, 若你也想創建一個自己的腳本,可以直接 fork 項目,修改相關配置即可。
小結
本文簡單介紹了油猴腳本開發步驟以及實現,結合 webpack 讓腳本實現工程化,並且配合 Github action,讓腳本實現自動化構建和部署。
但是若想要實現一些有用的腳本,還需要具備更多的知識,比如JS逆向分析
等,若你有好的想法,趕快行動起來吧!
以上就是本文全部內容,如果對你有幫助,可以隨手點個贊,這對我真的很重要,希望這篇文章對大家有所幫助,也可以參考我往期的文章或者在評論區交流你的想法和心得,歡迎一起探索前端。
評論區 @虛鯤菜菜子 推薦了一個基於 vite 的解決方案,比較完善,大家可以體驗下: https://github.com/lisonge/vite-plugin-monkey
[1] 去廣告插件:https://greasyfork.org/zh-CN/scripts/439420 - 屏蔽廣告 - 屏蔽谷歌廣告 - 百度廣告 - 知乎廣告 - 隱藏谷歌和百度搜索增強百度搜索結果的各種廣告等等 - 過濾所有采用谷歌聯盟和百度聯盟等廣告聯盟的廣告
[2] 選中複製插件:https://greasyfork.org/zh-CN/scripts/405130 - 文本選中複製
[3]Tampermonkey: https://www.tampermonkey.net
[4]greasyfork.org: https://greasyfork.org/zh-CN
[5]GitHub tampermonkey-starter: https://github.com/maqi1520/tampermonkey-starter
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/fUgiTixW6fAoGSf8Dont8g