第 1 章 開始
1.1. Greasemonkey 是什么?
Greasemonkey 是一個跨越chrome、firefox的擴展,它具有通過編寫腳本來改變被訪問網頁的功能。
可以:
1. 使訪問的網站更便於閱讀或者更便於使用;
2. 修復網頁渲染的缺陷,而無須煩擾網站管理員。
3. 讓網頁更好地使用殘疾人援助技術,清楚響亮地說出網頁內容,或者將網頁內容變為盲文。
4. 自動地獲得其它網站的數據,從而使兩個網站更好地相互鏈接起來。
然而 Greasemonkey 本身並沒有作這些事。實際上,在您安裝它之后,您注意到根本沒有任何變動…直到您開始安裝一種叫做“用戶腳本”的東西。用戶腳本(user script)就是一大塊 Javascript 代碼,還有些附加信息,用來告訴 Greasemonkey 腳本應該在何時何地運行。每個用戶腳本能夠針對具體頁面,具體網站,或者一批網站。用戶腳本能做到您在 Javascript中可做到的任何事情。實際上,它能做得更多,因為 Greasemonkey 提供了專供用戶腳本使用的函數。
這里是Greasemonkey 腳本庫含了上百個用戶腳本,這些都是用戶為了滿足自己的需要而寫的。一旦您寫了自己的用戶腳本,只要您認為別人也許發現它有用,您可以把它添加到腳本庫中。您也可以自己使用,因為從編寫過程中獲得知識,獲得滿足感,才是更重要的。
目前國內主要的油猴腳本網站是:Greasy Fork
1.2. 安裝 Greasemonkey
要使用用戶腳本,您首先需要安裝一個用戶腳本管理器。根據您使用的瀏覽器不同,可用的用戶腳本管理器也有所不同。
- Chrome:Tampermonkey 或 Violentmonkey
- Firefox:Greasemonkey、Tampermonkey 或 Violentmonkey
我使用的是chrome瀏覽器,安裝的是Tampermonkey 。安裝過程可能需要翻牆,我是在chrome的網上應用商店直接下的。
其他瀏覽器,請參考:深入淺出 Greasemonkey
1.3. 安裝用戶腳本
Greasemonkey “用戶腳本”是用 Javascript 編寫的獨立文件,用來定制一個或多個網頁。
[提示] 您可以在Greasemonkey腳本庫,找到許多用戶腳本。盡管沒人要求您必須把腳本放到那兒去,但是實際上,您可以把您的腳本共享到任何地方,這樣別人就可以安裝它了。甚至您根本不需要一台網絡服務器,因為你可以從本地文件中安裝用戶腳本。
用戶腳本的文件名必須以.user.js結尾。
鼠標左鍵點擊油猴圖標,出現如圖所示界面,其中“網頁限制解除”、“DownloadAllContent”等等,都是之前添加的油猴腳本。
添加新腳本的時候,點擊“添加新腳本”,彈出 新建用戶腳本 編輯界面。
界面內編輯器里,可以添加腳本,現在出現的是默認設置。
點擊獲取新腳本,轉到油猴腳本庫,可以從中選擇合適的油猴腳本。
參考資料
Greasemonkey 腳本庫有上百個 Greasemonkey 腳本。
2. 編輯用戶腳本
如果願意可以安裝很多個 Greasemonkey 腳本。 Greasemonkey 帶有配置對話框來管理用戶腳本:暫時禁用,改變配置或卸載腳本。
on/off 可以選擇啟用或暫停腳本。
點擊管理面板,可以對腳本進行管理,編輯,卸載
管理比較簡單,一看就懂。
第 2 章 編寫第一個用戶腳本
2.1. Hello World
我們步入 Greasemonkey 美妙世界的萬里長征將從第一步開始,所有讀過技術手冊的讀者都會很熟悉這一步:讓您的電腦打出“Hello world”。
例 2.1. helloworld.user.js
// Hello World! example user script // version 0.1 BETA! // 2005-04-22 // Copyright (c) 2005, Mark Pilgrim // Released under the GPL license // http://www.gnu.org/copyleft/gpl.html // // -------------------------------------------------------------------- // // This is a Greasemonkey user script. // // To install, you need Greasemonkey: http://greasemonkey.mozdev.org/ // Then restart Firefox and revisit this script. // Under Tools, there will be a new menu item to "Install User Script". // Accept the default configuration and install. // // To uninstall, go to Tools/Manage User Scripts, // select "Hello World", and click Uninstall. // // -------------------------------------------------------------------- // // ==UserScript== // @name Hello World // @namespace http://diveintogreasemonkey.org/download/ // @description example script to alert "Hello world!" on every page // @include * // @exclude http://diveintogreasemonkey.org/* // @exclude http://www.diveintogreasemonkey.org/* // ==/UserScript== alert('Hello world!');
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
正如您所見到的,這個Hello World腳本的大部分都是注釋。有些注釋,比如如何安裝,沒什么特殊含義;那只是對初學者的一些指導。但是,有一節注釋確實有特殊含義,下一節會有詳細的解釋。
要看到腳本的效果,您首先要安裝,然后訪問一個不在diveintogreasemonkey.org域名下的網站(例如,Google)。這個頁面將會像平時一樣顯示出來,還會彈出一個對話框:“Hello world!”
下載
- helloworld.user.js](http://www.firefox.net.cn/dig/download/helloworld.user.js)
2.2. 用元數據描述您的用戶腳本
每個用戶腳本都含有一段元數據,用來向 Greasemonkey 描述這個腳本自身的信息:發行者,執行規則等等。
例 2.2. Hello World 元數據
// ==UserScript== // @name Hello World // @namespace http://diveintogreasemonkey.org/download/ // @description example script to alert "Hello world!" on every page // @include * // @exclude http://diveintogreasemonkey.org/* // @exclude http://www.diveintogreasemonkey.org/* // ==/UserScript==
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
這里有六條獨立的元數據信息,作為一個整體包含在注釋中。現在讓我們按順序逐條解釋。首先講最外面的這層包裝。
// ==UserScript== // // ==/UserScript==
- 1
- 2
- 3
上述標記很重要,必須完全吻合。Greasemonkey 用它們來標記用戶腳本的元數據段。這段注釋可以放在用戶腳本的任何部位,但經常會放在靠近頂部的地方。
在元數據段內,第一項是名字。
// @name Hello World
- 1
這是您的用戶腳本的名字。它將會在您第一次安裝腳本時在安裝對話框(install dialog)中顯示出來。之后會顯示在“管理用戶腳本”對話框中。這個名字應該言簡意賅。
@name可選的。如果存在,它只能被定義一次。如果不存在,將會默認顯示用戶腳本的去掉擴展名.user.js的文件名。
下一個是命名空間(namespace)。
// @namespace http://diveintogreasemonkey.org/download/
- 1
這是一個 URL,Greasemonkey 用它來區分名稱相同但是作者不同的用戶腳本。如果您有一個域名,您可以使用它作命名空間。另外您也可以用 tag: URI。
@namespace是可選的。如果存在,它只能被定義一次。如果不存在,將會默認使用下載用戶腳本的網站域名。
元數據可以以任意次序排列。推薦使用@name,@namespace,@description,@include,最后是@exclude,但是其它的順序也沒關系。
下一項是描述。
// @description example script to alert "Hello world!" on every page
- 1
這是關於用戶腳本功能的描述。在您第一次安裝腳本時,它將會在安裝對話框中顯示,之后會在“管理用戶腳本”對話框中顯示。描述不應多於兩句。
@description 是可選的。如果使用它,那么它只能被定義一次。如果不使用,默認會顯示為空白。
[重要]
不要忘記寫@description。即使您所寫的用戶腳本是給自己用的。你最后很可能會擁有很多腳本,如果沒有描述的話,在“管理用戶腳本”對話框中管理腳本將會成為一件令人頭疼的事。
下面三行是最重要的 (從 Greasemonkey 的角度來看):@include和@exclude URL。
// @include * // @exclude http://diveintogreasemonkey.org/* // @exclude http://www.diveintogreasemonkey.org/*
- 1
- 2
- 3
這幾行讓 Greasemonkey 知道在那些網站上執行您的用戶腳本。您可以明確的指定一個 URL,或者用通配符 * 來代替域名或路徑中的部分字符。在這個例子中,我們告訴 Greasemonkey 在除了 http://diveintogreasemonkey.org/ 和 http://www.diveintogreasemonkey.org/ 的所有網站上執行。排除(Excludes)優先於包含(includes),所以即使 http://diveintogreasemonkey.org/download/ 匹配 * (所有網站),它還是會被排除掉,因為它還匹配 http://diveintogreasemonkey.org/* 。
@include和 @exclude 是可選的,可以自定義執行和豁免的 URL,但必須每條規則各占一行。如果您沒有任何定義, Greasemonkey 將會對所有的網站執行您的用戶腳本。(等同於 @include *)。
[注意]
您需要定義非常精確的@include和@exclude元數據。Greasemonkey 不會對域名作任何的假設,如果一個網站符合http://example.com/和http://www.example.com/,您需要把這兩個網址都標示出來。
參考資料
2.3. 編寫用戶腳本代碼
我們的第一個用戶腳本是在執行時簡單地顯示一條提示信息:“Hello world!”。
例 2.3. 顯示“Hello world!”提示信息
alert('Hello world!');
- 1
盡管這段代碼仿佛夠用了,而且也達到了目的。Greasemonkey 實際上在幕后做了很多的事情來確保用戶腳本不會與頁面所包含的原有腳本發生嚴重的沖突。特別是它會自動的把您的用戶腳本封裝在一個匿名的函數包里。一般情況下,您可以忽視,但是終究有一天會讓您遇到麻煩。所以最好現在就了解一下。
最經常遇到的麻煩之一是在用戶腳本里定義的變量和函數不能被別的腳本訪問。事實上,只要用戶腳本運行完了,所有的變量和函數就都不能使用了。如果您期望使用 window.setTimeout 函數,或者在鏈接掛上字符串式的 onclick 屬性然后期望 Javascript 稍后調用您的函數,那么您會遇到問題。
例如,下面這個用戶腳本中定義了一個函數helloworld, 然后嘗試設置一個計數器來在一秒后調用這個函數。
例 2.4. 延遲調用函數的錯誤方法
function helloworld() { alert('Hello world!'); } window.setTimeout("helloworld()", 60);
- 1
- 2
- 3
- 4
這段代碼沒有起任何作用;不會彈出提示窗口。如果您打開錯誤控制台,會看到一個異常:Error: helloworld is not defined.這是因為當延遲結束,開始調用helloworld()時,helloworld函數已經不存在了。
如果您需要引用用戶腳本中的變量或者函數,應該顯式的把它們定義為window對象的屬性,它是始終存在的。
例 2.5. 延遲調用函數的更好方法
window.helloworld = function() { alert('Hello world!'); } window.setTimeout("helloworld()", 60);
- 1
- 2
- 3
- 4
- 5
目的達到了!頁面完成加載一秒后,一個提示框驕傲的彈了出來,寫着:“Hello world!”
然而,在 window上設置屬性依然不太理想;這有點像用全局變量來做局部變量該做的事。(事實上,就是那么回事,window是全局的,可以被頁面中的所有腳本訪問。更實際的講,它可能會與頁面自身的腳本,甚至是其它的用戶腳本相互干擾。
最佳的解決方案是定義匿名函數,把它作為第一個參數傳遞給 window.setTimeout。
例 2.6. 延遲調用函數的最好方法
window.setTimeout(function() { alert('Hello world!') }, 60);
- 1
我在這里所做的是建立一個沒有名字的函數(一個“匿名函數”),然后直接把它傳遞給 window.setTimeout。這樣可以完成與上個例子相同的事,而不會留下痕跡。例如不會被其它的腳本檢測到。
我發現我在寫用戶腳本時經常使用匿名函數。它們很適合創建“一次性”函數,然后當作參數傳遞給類似window.setTimeout,document.addEventListener 或者賦值給事件句柄像 click 或 submit。
參考資料
2.4. 保存用戶腳本
對於腳本的作者來講,“管理用戶腳本”對話框有個很實用的功能:編輯按鈕可以“動態的(live)”修改已安裝的腳本。
修改/編輯完腳本文件后,點擊保存按鈕,腳本文件就自動加載到油猴里面。
這時候打開新網頁,就會彈出hello world對話框。
第 3 章 修改網頁操作
在chrome上編輯油猴腳本的時候,可以按F12鍵,調出chrome的控制台幫助調試,一些錯誤命令會在控制台上顯示出來,比較方便。
油猴腳本庫中,有一個下載小說的腳本,我覺得對我這種重度小說依賴症來說,是個福音。因此,我練手的時候,打算以此為藍本,練習自己的代碼。計划是這樣:在小說網站的網頁上添加一個下載小說的按鈕,如果想下載小說,可以按此按鈕一鍵下載。
首先,先看一下,如何在頁面上添加一個按鈕。
3.1 給網頁添加一個按鈕
這個腳本用作練習,功能是在網頁上指定位置添加一個按鈕。
腳本如下:
// ==UserScript== // @name Hello World_cjn2 // @namespace // @description // @include https://www.bixia.org/* // @include https://bixia.org/* // ==/UserScript== (function() { 'use strict'; var button = document.createElement("input"); //創建一個input對象(提示框按鈕) button.setAttribute("type", "button"); button.setAttribute("value", "下載"); button.style.width = "60px"; button.style.align = "center"; button.style.marginLeft = "250px"; button.style.marginBottom = "10px"; button.style.background = "#b46300"; button.style.border = "1px solid " + "#b46300";//52 button.style.color = "white"; var x = document.getElementById("maininfo"); x.appendChild(button); // Your code here... })();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
效果如下,加載完頁面后,會在畫圈的位置添加一個按鈕:
代碼的前半部分,都是用來給按鈕添加各種屬性。后半部分指明了添加在網頁中的位置,這里給元素節點 maininfo 追加一個子節點 button
var x = document.getElementById("maininfo"); x.appendChild(button);
- 1
- 2
有時候,調試不成功要注意查看控制台輸出錯誤,看看哪里不對。