【本文为付费内容,如您尚未付费请点此】
【返回目录】 | 【上一章 油猴子用什么写】
油猴子的基本格式
校对完成,更新时间:2020-07-23 11:22:25
首先记住它会分为两部分:
- 上面以注释形式出现的元数据
- 下面要注入页面中的脚本代码
在各种编辑器中这两部分都会以不同的颜色进行显示,所以很容易区分,我们先来研究元数据。
元数据,这个名词又很新鲜,英文 meta。就是对脚本的一些基本信息的说明,或者你叫它头部信息什么的,只要能够顺畅的交流,叫什么名字其实并不太重要。而且好多翻译也确实做不到信达雅,反倒让人增加迷惑。所以不要太在意这些,小老鼠自己也完全搞不清楚这些名词,反正会写就完事儿了。
那么起到说明性的作用,就是说明书?!那就是不用读系列……
并不是哦!虽然也许不书写元数据部分在某些平台下它也是可以使用的。但元数据信息真的是非常重要。这就好像做好我们本职的工作这是份内的事情,而处理好人际关系,似乎并不在这个本职工作之内,但是大家都懂的,如果人际关系处理不好,那你的本职工作也很难顺利完成。所以在工作前先和各部门打好招呼,我要做什么事情了,大家要给予支持,然后相互协调,避免冲突。这些话虽然很套路,但是总还是要说一下的。
居然是套路,那应该就有模板。你在脚本管理器里去新建一个脚本,它就会自动填写上一些基本的元数据。比如我在暴力猴中新建一个脚本,得到的内容是下面这个样子的:
// ==UserScript==
// @name New script - meta.appinn.net
// @namespace Violentmonkey Scripts
// @match https://meta.appinn.net/t/topic/17705
// @grant none
// @version 1.0
// @author -
// @description 2020/7/20 上午7:22:46
// ==/UserScript==
虽然全是英文,但也不用紧张,咱们要看的主要是格式。反正程序员一般都有强迫症,所以代码里你会看到许多整整齐齐的格式,很舒适的。
这里的第 1 行和第 9 行就是个固定格式,表示元数据的开始和结束,并且说明这是用户脚本。对,这又是一个我必须要给你们讲一下,但是你们并不一定需要记住的问题。反正每一次新建脚本模板都给好了,要不是需要给你们讲,我早都忘了这两行的事情……
每一行用双斜线开头,是表示这是注释不参与运行,这就避免了某些不兼容的情况下,这些元数据对脚本产生影响。
然后中间几行,前面有一个以 @
开头的单词,然后一些空格,后面写了些内容。前面的单词是说这一行记录了什么信息,后面的内容就是对应的信息。
那么现在看第 2 行,@name
显然是说名字,空格后面的内容就是这个脚本的名字,我们可以根据自己的需求进行修改。
理解这一条后面的就都好理解了,因为书写的格式是一样的。现在的问题就是,我要知道都可以去设置哪些数据。对这个事情总是要有一个规范的,要不然像小老鼠这么碎嘴子的,能在上面写个长篇小说,固然会把该说的都说清楚了,但是脚本管理器表示宝宝并看不懂,不就鸡对鸭讲了么……(咦,好像哪里不太对的亚子
可用的元数据
在告诉大家有哪些元数据的字段(标签)可用之前要先做一些简要的说明:
- 我们并不需要把所有可用的字段全写上,只要写自己用得上的那部分就好;
- 有些字段是可以多次出现的,但有些就只能出现一次,这些我会进行标注,大家根据字段所表达的意思去理解为什么是这样;
- 不同的脚本管理器,对元数据的支持也不相同,但基础部分大家基本是一致的。而且你即便写上了这个脚本管理器无法理解的字段,也不会产生负面影响。
如果你以前看过一些相关的内容,那么很容易理解我将要做什么,就是把这些元数据的字段罗列出来,挨个给大家解释。差不多等于把文档复制过来并翻译一遍。
但如果我真的那么做,我估计连篇累牍的内容能立刻劝退 1/3 的小伙伴。讲还是要讲的,我们就稍微换一个角度,对这些元数据做一个粗略的归类。
必须有的元数据
这也不是绝对的必须,不写也不是说完全不行。但如果你要去写元数据,我觉得应该没有人会拒绝把这几个项目写上去。
@name
脚本总要有个名字吧。要不以后怎么称呼它?嘿,那个脚本……
但这里存在一个误解,就是把它看得过分重要。其实比较准确的理解是这里大概相当于昵称。就是用来让人便于识别和称呼的,它也会用来显示在脚本列表等地方,让我们能够快速的了解这是哪一个脚本。
@namespace
命名空间,这名词又让人迷惑。而且上面已经有一个名字了,那就更让人迷惑。那你把它理解为用户(脚本) ID 好了。
我们和上面对照一下,昵称是用来称呼的,ID 是用来识别它就是它的。这就好像在微信里,我们可以经常的去修改昵称,但是微信号轻易是不能修改的。
在文档中的描述是:用 @name
和 @namespace
的组合来识别脚本,但在不同的脚本管理器下可能有所区别。总之这两个内容设置好之后,尽量就不要修改了。尤其是 @namespace
,如果修改肯定要引发问题。
自然也很容易理解,这两者不要和其他的脚本冲突。两个学生具有相同的名字或者相同的学号,就会让人很难分辨,然后引发错误。
@version
版本号,基本格式就是: 1.0.0 这样。第 1 位表示大版本,第 2 位表示小功能的增加,第 3 位表示细节的修补。
但是对于版本号也没有那么严格的要求,按着这个格式去书写就可以了,至于数字代表什么,或者你随便去写,都没所谓。比如现在浏览器的大版本号(第一位)就是随着时间固定的增长。而我自己写东西一般第 1 位就永远是 0,因为我一直认为自己写的东西不够完善,不足以发出一个正式的版本。
但是新版本的版本号一定要比旧版本的大,因为这是判断升级的一个依据。如果脚本管理器发现,线上的版本比当前已安装的版本版本号更高,那么这个脚本就可以进行升级。
@author
作者,这后面写上你的大名,愿意加上邮箱,也没人管你。或者加上一堆形容词。反正就是写清楚脚本的作者是谁,你一定不会希望别人用了这个脚本,却不知道它是你写的,那就真的变得默默无闻了。
@description
对于这个脚本的描述,它会显示在应用市场的简介中,就是脚本名字下面最先显示出来的那部分。在脚本列表中,显示的脚本信息也对应着这里的内容。
这里进行一些补充说明。上面这 4 个都只能出现一次哦,很容易理解的吧,我们总不能给一个脚本弄出两个名字来,两个版本号就更加荒唐了。如果有多个作者,那就都写在那一行里就好。对,一行。就算是描述也要写成一行,不要用回车换行。(别抬杠,抬杠就兼容性,不一定所有脚本管理器都支持特殊的格式,所以用最基本的格式最不容易出错)
@name
和 @description
因为是描述性的内容,所以支持多语言,就是你可以为每一种语言单独设置一份名字和描述,具体格式如下:
// @name My first user script.
// @name:zh-CN 我的第一个脚本
// @name:en-US Meow~
// @description dms is a sunshine boy.
// @description:zh-CN 小老鼠帅帅哒~
// @description:en-US Delicacies
描述中建议写上脚本的创作日期和更新日期,这样方便自己日后回顾。如果你有强迫症,觉得在描述中混入这样的信息,让自己不舒服,也完全可以自己创造两个字段来标记,反正脚本管理器不理解就会把这些字段跳过去,但是自己看代码的时候是有意义的。
@match
这是描述这个脚本要在哪些网址下运行。如果和后面的网址匹配就运行。
但大多数时候我们的脚本并不只运行在某一个确定的网址下,而是希望在某个网站上都起作用,或者这个网站的某个分类下都起作用,这时候就要用到通配符。
网址会被分为三部分:协议、域名、路径。
https://www.appinn.com/auto-expand-full-text/
这样的一个网址,其中 https
就是协议,那我们知道还有 http
的协议。
www.appinn.com
这部分就是域名,表示的这是哪一个网站。
auto-expand-full-text/
这部分,就是在域名后面那条斜线之后的部分,用来表达这个网站中的哪个页面,这就是路径。
然后对于每一部分,我们都可以完整准确的去写出它的内容,或者使用星号代替一定的字符。
如果在协议部分使用星号,那么代表的是:http
或者 https
,对,只有这两种协议,并不包含其他。
如果在域名部分只有星号,那么它匹配任何网站。如果域名的子域是星号(比如上面域名的 www 部分),那就表示这个域名下的任何子域(www 可以被换成任何内容)。
如果是路径位置的星号,它可以匹配 0 到任意多个字符。
*://*/*
所以像上面这样写就表示匹配任何协议下的任何网站的任何路径,就是在所有能运行的页面全都运行这个脚本。
*://www.appinn.com/*
上面这样写表示在这个网站下的所有页面都运行。
*://www.appinn.com/posts/*
上面这样写表示在这个网站下的 posts
目录下的页面中全都运行。
这个规则并不难掌握,因为它没有搞得很复杂。几种简单的情况,稍微熟悉一下就可以很好的掌握了。但这时候我们就会遇到一个很普通又很棘手的问题,都有很多网站,我们在域名部分写出下面两种形式都可以正常的访问:
www.appinn.com
appinn.com
就是加不加 www 都可以。但这就很难使用通配符进行表达。
*://*.appinn.com/*
这样前面不是 www 的也会被匹配,并不符合我们的预期。而且注意在星号后面多了一个点,所以这种书写方式并没有办法匹配到完全不加 www 的情况。
有同学可能说,反正星号可以代替各种字符,那我就这样写:
*://*appinn.com/*
先不考虑这个写法是不是真的符合规则。就算可以正常使用,那么会不会匹配到下面的网址:
https://meow-appinn.com/
这显然就完全是另外一个网站了,所以这样写的疏漏太大,是完全不可取的。正确的方法是,索性写两条规则好了,就像下面这样:
@match *://www.appinn.com/*
@match *://appinn.com/*
所以,@match
可以出现多条。把你需要适配的情况写完全,一条规则一行,就像上面这样书写就好。
可选的地址信息
写不写都可以,写上会更完善一些。
@homepage, @homepageURL, @website, @source
这是个选择题,4 选 1,因为表达的意思是一样的。由此可见,对于脚本的元数据,大家创造了很多规范,也并不是那么十分统一。还有就是随着规范的不断更新,又要去兼容以前的规范,导致多种规范并行。
这个字段设置的是脚本的主页,就是官方网站的意思。但很多脚本也并没有主页,于是就放上作者自己的网站博客等。有人说这就是免费的广告位,谁会放弃呢?(我的脚本好像大部分都没有写,亏了亏了
这个信息会显示在脚本市场或者脚本列表中的主页信息上,一般只要点击就会直接跳转到对应的网站。
然后如果在 @namespace
中填写的直接是一个网址,也会被视为这个脚本的主页。
@icon, @iconURL, @defaulticon
三选一,设置脚本的图标,放上图标图片的网址。这时候你可能需要一个好用的图床,这确实挺麻烦,所以好多脚本就并没有设置。
当然如果设置了会显得很好看,也很专业的样子。
@icon64, @icon64URL
表示 64×64 像素尺寸的图标,和上面一样给出一个图片的地址。和上面的区别是这代表更高清晰度的图标。但一般来说我们也不怎么会用上,而且也不是所有脚本管理器都支持。如果设置图标,就设置上面的字段就够了,这个就作为了解一下,又是你可以不用,但我不能不说的内容。
@supportURL
支持页地址,如果用户有问题去什么地方找你进行反馈,那么把这个地址放在这里。脚本市场和脚本列表中对应的位置会进行显示。
@downloadURL
脚本的下载地址,就是你的脚本文件在网络中的访问地址。脚本管理器会通过访问这个网址来更新脚本。
但一般也没有人写,因为如果是通过网络地址安装的脚本,脚本管理器会自动为这个脚本添加它的下载地址,以备日后进行更新。我们上传到脚本市场的内容,即便没有填写这些信息,也会被添加/修改为市场的地址。这可以让用户更方便稳定的获得脚本更新。
@updateURL
脚本的更新地址。首先这个不是所有的脚本管理器都支持,很多脚本管理器直接通过上面的下载地址判断是否需要更新。
脚本管理器通过访问这个地址,获取当前最新版本的版本号,然后得出一个是否有更新的结果。所以只是借此进行判断,而不是通过这个网址进行更新。
大部分情况下无需填写此信息。只不过是既然这些网址都出现了,索性把它们放在一起讲一下。
为了避免疑惑,也方便大家出去装 x,所以我把这个没什么用的东西也解释一下。这个更新地址里放什么呢,也放你的脚本,就和上面的 @downloadURL
是一样的。然后脚本管理器访问 @updateURL
来获取脚本的版本号和更新日期,来判断是否需要更新。如果需要,那么通过 @downloadURL
的地址来下载更新。
好像这样复杂的设计,非常莫名其妙,因为这两个网址可以完全一样,并且会正常的工作,搞成两个,这不是多此一举么?那现在我们来设想一个特殊的情况:我的脚本非常复杂,所以体积很大,下载一次需要好几分钟那种。然后用户又有强迫症,希望保持脚本的及时更新,那每一次检查更新需要花费的时间就很长。然后我很懒惰,三年才更新一次脚本,三年里用户的脚本管理器每天都在检查更新,这是怎样的资源浪费啊!但把检查更新和实际进行更新这两个网址分开,就意味着我可以在 @updateURL
这里放一个只包含脚本元数据的版本,这样检查的速度就非常快了,反正也就是对照一下元数据,看看是否需要更新嘛。如果发现确实有更新的需要,再去下载地址,下载那个体积巨大的完整版本。
这么一解释就会发现这个设计是合理的,但为什么现在又不需要呢?下载地址完全可以让脚本管理器自动去解决,你从哪里安装的这个脚本,它就把这个地址自动的记录下来,然后随时从这个地址去检查更新,这样无论是作者还是用户都会更加方便。至于检查更新的时候,脚本管理器可以只下载前面的一段数据进行比较,反正元数据都写在最前面,我读取到版本号就好了,后面的内容不下载。就是通过脚本管理器的增强和优化,让这些以前有意义的设计变得没有什么必要了。
出于强迫症或者一致性的考虑,主页字段我会选择使用 @homepageURL
这个名称,图标字段用 @iconURL
。当然如果新建脚本的时候给出的模板已经写了,那我也懒得去修改,直接填上内容就好。
需要时才会出现的内容
以下内容仅在你需要进行这项设置的时候才书写它。否则就没有必要让它们露面了。
@exclude-match
这个和我们前面讲到的 @match
书写和使用都是一样的,但表达的意思是不要在这些网站上去运行脚本。可以认为 @match
是一个白名单,而 @exclude-match
则是一个黑名单。
如果我们只打算匹配几个确定的网站,那么使用白名单(@match
)肯定最方便;而如果要匹配几乎所有的网站,只有极个别的网站要排除掉,这时候就要配合使用。先用白名单(@match
)匹配所有网站(*://*/*
),再用黑名单(@exclude-match
)将特定的网站排除掉。
@match
是必须有的,@exclude-match
则根据情况去进行设置。这两项在(针对单个)脚本的设置中,也会有相应的选项,这是供用户进行设置的,用户的设置可以覆盖脚本自带的设置,并且不会受到脚本更新的影响。
@include / @exclude
和 @match
/ @exclude-match
差不多,建议使用 @match
/ @exclude-match
而不是 @include
/@exclude
因为匹配规则更安全,更严格。
你可以把这认为是旧的方式,可以用,但不推荐,然后一些脚本管理器可能不支持 @exclude-match
,那就只好用 @exclude
了。
@require
引入的库。
写脚本就是为了给自己带来便利,那如果每一个功能都自己写,确实挺不容易的。要是把别人写好的工具库引入进来,然后再做一些简单的调用,那就方便多了。
这个字段后面应该写一个 js 文件的地址,就是你要引入的那个库。然后脚本管理器就会自动的把它插入到页面之中。其实我们通过自己书写脚本来实现这个功能也不算很麻烦,但是能少写几行代码总是很开心的。
因为可能需要引入多个库,所以这个字段可以书写多个。
@resource
这个字段用来将一些在脚本中会使用的资源进行预加载。就是打开页面以后,它就会开始下载这些资源,这样等到我们需要使用的时候,就不需要再去等待那个下载的时间了。
具体的使用需要配合接口,这个我们在后面会讲到,这里只先演示它的书写:
// @resource logo https://img3.appinn.net/static/wp-content/uploads/appinn190.png
后面的内容首先是我们给这个资源取的名称,用来在脚本中调用。然后是这个资源的地址,可以是图片或者某些文件的网址。
当然我们需要引入的资源可能不止一个,所以这个字段也可以书写多个。
上面说到了接口,就是脚本管理器给我们脚本提供的一些便利,和更高的权限,让我们能够更好的完成工作。就好像可爱的女仆打算为小老鼠做饭,她就要跟管家申请使用厨房,管家允许她使用厨房,并且有权使用厨房中的各种食材,厨房里的厨师们也要听从她的指挥来进行辅助。那么烹饪这件事情就变得简单而畅快起来了。
当然如果你需要这些权限,这些辅助,要先和管家明确的提出申请,这样管家才知道如何安排才能够更好的帮助到你。@grant
这个字段就是用来申请接口的权限,说明我要使用这个接口,然后才可以在脚本中进行使用,它的书写格式是这样的:
// @grant GM_getValue
// @grant GM_setValue
在它后面写上要使用的接口名称就可以了,每一行只能申请一个接口,如果需要多个接口,那就像上面这样书写多行。
@run-at
这个字段是用来设定我们的脚本在什么时候注入到页面之中,有如下几个值可供选择:
document-end
这是 Violentmonkey 的默认值,就是当页面加载完成之后,再注入我们的脚本。一般来说这个时机是不错的,页面加载完成以后不会再发生大的变化了,然后我们对它进行修改,就不容易出现混乱,或者被后续的改变而覆盖。但如果某些页面使用了懒加载技术,那么可能虽然已经宣称页面加载结束,其实还在进行着各种加载工作,这时候就要具体问题具体处理了;
document-start
这表示让我们的脚本尽可能早的被注入,但这并不能够保证我们的脚本就在其他所有脚本之前运行。
document-idle
这是 Tampermonkey 的默认值。这个时机可以简单粗暴的认为是在页面加载完成之前的那一瞬间。虽然在页面加载完成之后去注入是一个不错的时机,但是可能有许多脚本都在等待着这个时机运行,我们不想和其他脚本争抢,所以就走一个 VIP 通道,当页面加载完成,但还没有对外宣布的时候,就是还没有到 document-end
这个时间点的时候,注入我们的脚本。然后再对外宣布页面加载完成,即到达 document-end
这个时间点。
document-body
如果存在 <body>
元素,则执行脚本。Tampermonkey 支持此选项,Violentmonkey 中则未提及。
context-menu
当在浏览器的右键菜单中点击该脚本的项目,才进行脚本的注入。这个方法最大限度的保证了脚本不被使用就不被加载。Tampermonkey 支持此选项(但未来可能改变,并且文档中没有说如何设置右键菜单),Violentmonkey 中则未提及。
@noframes
这个字段后面不需要写任何的内容。如果没有写这个字段,则脚本默认是在页面和页面里的所有的框架中运行(如果这个框架的网址也符合我们设定的条件的话)。
添加上这个标记,则只在页面中运行,而忽略掉所有的框架。
如果你没有听懂这是在说什么,就在发现某个页面中这个脚本被运行了多次,不符合你预期时加上这个。
一些不是所有脚本管理器都支持的标记
其实上面已经讲到一些,比如 @icon64
、@updateURL
,以及上面运行时机中的一些选项。后面这些则是对于新手几乎是完全没有用的,即便是老手也很少需要用到它们,或者在用到的时候需要十分慎重,因为要认真的考虑兼容性和可能引发的其他问题。
@connect
后面是书写一个域名,用来声明我们会在脚本中使用到这个域名中的资源。这可以用来解决跨域问题。
这个功能我没有使用过,而且我也希望所有作者都能够谨慎使用此功能。虽然在前端上禁止跨域是一件非常烦人的事情,但这个限制在安全层面考虑还是非常有必要的。现在工具可以给我们更高的权限来突破这个限制,但是“能力越大,责任越大”,我们也有必要十分谨慎的对待这个强大的权限。
此字段可书写多个,Violentmonkey 似乎并不支持。
@nocompat
标记不兼容的浏览器,因为每个浏览器在技术上总是有着细微的差别,所以导致有些脚本只能在特定的浏览器上去运行。我们通过这个标记来告诉脚本管理器,当前的脚本不兼容哪些浏览器。
此属性似乎 Tampermonkey 独有。
@inject-into
用来指定脚本的注入模式,有如下三种选项:
page
:这是默认值,脚本会被直接注入到页面之中,各方面都和页面原生的脚本是一样的;
content
:在一个与页面隔离的环境下运行,可以访问和修改页面的 DOM,但是无法访问到网页的 JavaScript 对象。 不过可以通过 unsafeWindow
对象来绕过限制进行访问,但这种做法(绕过)是非常不推荐的。
auto
:先尝试使用 page
模式进行注入,如果出现问题,则改用 content
模式来进行注入。
这个字段似乎是 Violentmonkey 独有。Tampermonkey 默认用 content
模式注入,在必要的情况下用 unsafeWindow
来访问 window
对象。
应用市场提供的标记
这里仅参照 Greasy Fork 的说明,不同市场会有不同的规定。
@license
脚本的许可协议,如果没有填写,则表示仅允许个人使用,且不得二次分发。
@contributionURL
用来收取捐助的链接。
@contributionAmount
建议的捐助金额
@compatible
脚本兼容的浏览器,并可附加更多说明。如:
@compatible firefox 火狐上必须关闭广告过滤器
目前能被网站识别的浏览器名称有:firefox
, chrome
, opera
, safari
。
@incompatible
不被兼容的浏览器,并可附加更多说明,格式参照上一条。
附录:上面提到的所有元数据的速读版本
-
@name 【通用】【多语言】脚本名称
-
@namespace 【通用】命名空间
-
@version 【通用】版本号
-
@author 【通用】作者
-
@description 【通用】【多语言】脚本描述
-
@match 【通用】【可多条】匹配规则
-
@homepage, @homepageURL, @website, @source 【可选】主页
-
@icon, @iconURL, @defaulticon 【可选】图标
-
@icon64, @icon64URL 【非通用】高清图标
-
@supportURL 【通用】【可选】支持页地址
-
@downloadURL 【通用】【不必填写】脚本下载地址,一般无需书写
-
@updateURL 【非通用】【不必填写】脚本的升级地址,无需书写
-
@exclude-match 【非通用】【可多条】排除规则
-
@include 【通用】【可选】【可多条】匹配规则
-
@exclude 【通用】【可选】【可多条】排除规则
-
@require 【通用】【可选】【可多条】引入的脚本
-
@resource 【通用】【可选】【可多条】预加载资源
-
@grant 【通用】【可选】【可多条】接口权限申请
-
@run-at 【通用】【可选】脚本注入时机
-
@noframes 【通用】【可选】不在框架内注入脚本
-
@connect 【非通用】【可选】【可多行】白名单外部域
-
@nocompat 【非通用】【可选】不兼容的浏览器
-
@inject-into 【非通用】【可选】脚本的注入模式
-
@license 【市场】脚本的许可协议
-
@contributionURL 【市场】脚本的捐助链接
-
@contributionAmount 【市场】建议的捐助金额
-
@compatible 【市场】兼容的浏览器
-
@incompatible 【市场】不兼容的浏览器
以上内容,小老鼠花费了一天多的时间辛苦整理。肯定还有很多疏漏,也有很多不准确的地方。但我也很难将它做的面面俱到,毕竟在不同的浏览器下,不同的脚本管理器下,面临的情况都不相同。而且还有油猴标准不断更新的因素在影响。所以这些内容只是作为给大家的参考,但实际书写的时候还是要以实际运行的效果为标准,根据自己面对的情况灵活的选择。
【返回目录】 | 【下一章 如何调试脚本】