Loon 脚本 API 与差异
上一章你学的是 Surge 的脚本写法。这一章换到 Loon,先告诉你一个好消息:两家的脚本 API 几乎一模一样,你已经会的东西基本不用重学。这一章要做的,就是把仅有的几处差异记牢,再学会一件事——判断一段代码现在跑在哪个客户端里。代码里的英文单词还是老规矩,当固定写法记,意思都用中文讲。
1这一章学什么
一句话目标:知道 Loon 和 Surge 的脚本 API 几乎一样,记住仅有的几处差异,并且会判断当前代码跑在哪个客户端里。学完这一章,别人写给 Surge 的脚本,你拿到 Loon 里多半能直接用;看到两边不一样的地方,你也知道该改哪里。
2概念
先说相同的地方,再用一张表把不同的地方一次讲清。
① 好消息:九成写法完全一样
Loon 的脚本 API 和 Surge 高度相似,四个最常用的工具基本照搬,名字和用法都没变:
$httpClient——发网络请求的工具;$persistentStore——把数据存下来、下次还能读的工具;$notification——弹通知的工具;$done——脚本结束时交结果的工具。
所以,上面两章(Surge 章节)的示例代码,搬到 Loon 里几乎原样就能跑,不用改。你之前学的没有白学。
② 差异只有这几处,记这张表就够了
| 看哪方面 | Loon | Surge |
|---|---|---|
| 环境标识判断在哪个客户端 | 有一个全局对象 $loon,里面装着系统版本、设备等信息。脚本里只要发现 $loon 存在,就说明现在跑在 Loon 里。 |
没有 $loon 这个东西。 |
| 参数外面传进来的设置 | 插件支持 [Argument] 段,可以把参数做成界面上能开关、能填写的选项,不用手改代码。脚本里照样用 $argument 读,读到的可能是对象,也可能是字符串,看它是怎么配置的。 |
用 argument= 传参数,传进来的是一串字符串(一段文字),脚本里用 $argument 读。 |
| 脚本分类脚本挂在哪种时机运行 | 类型名字和 Surge 一样,比如 http-request(请求发出前跑)、http-response(响应回来后跑)。另外多了像 enable 这样的开关参数,可以单独控制某个脚本开还是关。 |
类型名字相同:http-request、http-response 等。 |
| 日志看脚本打印了什么 | 同样用 console.log 打印,打印的内容在 Loon 的日志页里看。 |
同样用 console.log 打印,在 Surge 的日志里看。 |
| $done 形式脚本收尾交结果 | $done({...}) 的写法基本一致。比如改响应内容,同样是 $done({ body }),把改好的 body 交回去。 |
一样:$done({...}) 收尾,http-response 改 body 同样 $done({ body })。 |
看完这张表你会发现:五处里面,日志和 $done 其实完全一样,真正要留心的只有三处——$loon 这个标识、参数的给法、脚本的开关参数。
③ 因为太像,所以大家都写「双兼容」
正因为两家太像了,社区里分享的脚本普遍都写成「双兼容」:开头先判断环境(比如看 $loon 在不在),后面该用哪种写法就用哪种。写的人省事,用的人也不挑客户端。第十五章会给你一份现成的判端模板,到时候照着套就行。
3动手试
点「运行」,代码会真的在这一页里跑一遍,结果显示在下面。注意:这一页是浏览器环境,不是 Loon、也不是 Surge,所以有些结果会和在客户端里跑的不一样——这正是这三段要演示的事。
试一:先看两个「招牌工具」在不在
typeof 是老朋友了,用来问「这个东西是什么类型」。如果一个东西根本不存在,typeof 会回答 "undefined"(意思是「没有这个东西」)。
console.log(typeof $loon) // Loon 招牌,在不在? console.log(typeof $httpClient) // 发请求工具,在不在?
看结果:两行都是 "undefined"。不奇怪——这个页面是浏览器环境,Loon 和 Surge 的工具一个都不在这里,所以两个判断都是「不在」。$loon 不在,说明不在 Loon 里;$httpClient 不在,说明也不在 Surge 里。这段代码要是搬进 Loon,两行就都会变成 "object"(意思是「东西在,是个对象」)。
试二:判端代码——「我在 Loon 里吗?」
判断在不在 Loon,就看 $loon 存不存在。把这一句记牢,它就是第十五章判端模板的第一行:
// $loon 存在 → true,不存在 → false const isLoon = typeof $loon !== "undefined" console.log("在 Loon 里吗:" + isLoon) // 打印答案
看结果:输出 false——这一页是浏览器,$loon 不存在,所以「在 Loon 里吗」的答案是「不在」。同一行代码搬到 Loon 里跑,结果就会变成 true,什么都不用改。这就是「判端」:不靠猜,让代码自己看一眼环境再回答。
试三:$argument 两种给法,一种读法都接住
参数有个麻烦:Surge 给的是字符串(一段文字),Loon 的 [Argument] 给的可能是对象。兼容读法的思路是:先用 typeof 看一眼——是字符串,就用 JSON.parse 把它转成对象;已经是对象了,就直接用。
// 兼容读法:是字符串就转,是对象就直接用 function readArg(arg) { if (typeof arg === "string") { return JSON.parse(arg) // 字符串 → 对象 } return arg // 对象 → 原样交出 } // 第一种:字符串给法(Surge 的 argument=) const a = readArg('{"vip":true}') console.log(a.vip) // 能拿到 vip 吗? // 第二种:对象给法(Loon 的 [Argument]) const b = readArg({ vip: true }) console.log(b.vip) // 能拿到 vip 吗?
看结果:两行都是 true,两种给法都成功拿到了 vip。第一种先被 JSON.parse 从文字转成对象,第二种本来就是对象、直接用。不管参数以哪种面貌进来,readArg 都先把它统一成对象,后面的代码就不用再操心它是从哪边来的了——这就是「兼容读法」。
4练一练
五道选择题,点一个选项马上判对错。选错了会告诉你错在哪,再换一个试试;选对了会告诉你为什么对。
5适用案例
这一章讲的差异不是背着玩的,下面三个场景都是你日常会碰到的。
同一个去广告脚本,Loon 里几乎原样跑
你在 Surge 上用着一个去广告脚本:拦截请求、把响应里的广告字段删掉、最后 $done({ body }) 交回去。换到 Loon 上,这个脚本几乎一行不用改——$httpClient、$notification、$done 全是同名同用法,http-response 改 body 也是同样的 $done({ body })。你要做的只是把脚本挂到同样的类型上,跑一遍,看日志确认没报错,就能用了。
$argument 两边给法不同,兼容读法都接住
一个脚本带了个开关参数,比如「要不要开会员模式」。在 Surge 里,这个参数是 argument= 传进来的一串字符串;在 Loon 里,它是插件 [Argument] 段做成的界面开关,读出来可能是对象。如果脚本只按一种给法写,换个客户端就读不到参数、开关失效。用上面「动手试」试三的兼容读法——是字符串就 JSON.parse,是对象就直接用——两种给法都接得住,脚本不用改第二份。
判端模板:一份代码,两个客户端都跑
你想把自己的脚本分享给朋友,但你用 Loon、他用 Surge。办法是开头先判端:
// 先看 $loon 在不在 const isLoon = typeof $loon !== "undefined" // 在 → Loon 写法;不在 → Surge 写法
先判断、再分支,两边的小差异在各自的分支里处理掉,一份文件就够了。这正是社区脚本「双兼容」的标准做法,第十五章会给你一份完整的判端模板,到时候你写的脚本也能一份跑两处。
✓小结
一句话小结:Loon 和 Surge 的脚本 API 几乎一样,真正要记的差异只有 $loon 判端、参数给法和开关参数这几处;先判端、参数用兼容读法,一份代码就能两处跑。