这只猴子有点油

久仰大名Tampermonkey(油猴),之前一直没有机会用在工作中,所以一直都只是知道有这么个强大的东西。前段时间在和我们的客户讨论需求时,根据对方的描述,我觉得必须要油猴出马了。
有了动机,接下来就是学习,油猴的开发文档内容非常精炼,基本上30分钟就能通读完毕(上次让我有这种感叹的,应该是Vuejs)。
而之所以内容篇幅很小,我猜应该是因为“大道至简”吧,工作越久就越发能体会到这个概念的伟大,概括了事物的本质:简约(有点扯远)。
当你了解完油猴的自我价值定位后,你应该就能多少体会我的意思了:当我们解决问题时,视图抓住事物的本质(第一性原理)时会发现解决方案往往出其不意的简约(不是简单)。

那么请允许我说一下我是怎么理解油猴的:提供一种扩展目标网站的能力。可能是界面上的扩展,也可能是功能上的扩展,总之油猴只是提供最基本的接口,剩下的交给用户来发挥。
正因为油猴没有做更多的假设,所以才会这么纯粹,不仅仅文档内容精炼,接口也好不多余。

基本的用法,网上前辈们已经写了不少,我在最后的参考资料里会列出我觉得不错的文章链接,方便有需要的童鞋查阅。那么接下来,我主要写一些我实战后的心得体会吧。

安全

当用户使用你发布的油猴脚本时,最关注的应该就是它是否安全了,毕竟油猴太强大,能做太多事,不加思考的随意使用第三方提供的脚本,可能会给自己带来灭顶之灾(毫不为过)。
而油猴自身也明白这一点,所以它要求脚本明示自己会使用哪些油猴提供的能力,此外也做了沙盒环境来阻断脚本直接去修改源网站系统的Js变量。
但这对于粗心的用户 + 恶意开发者这种组合来说,对于安全提升似乎并没有什么太大的帮助。所以,衷心提醒广大童鞋,一定要当心噢!!!

那我们转过来说一下,当油猴的一些安全设定和我们的目标冲突的时候,该怎么办呢?
对我的业务场景来说,无法修改源网站系统中的JS变量,这对我造成了困扰。不过转念一想,既然油猴允许我们操作DOM,那我们只需要修改DOM追加一段脚本即可,在脚本里我们可以做任何想做的事儿(如: 覆盖window变量)。

额外的一点也需要提一下,如果你也需要获取浏览器端的cookie,尤其是设置为httponly类型的cookie,那传统的JS是绝对无法做到的,而油猴文档里其实有这方面的接口能力:GM_cookie
但由于这个对安全的影响实在是太大了,稳定版的油猴是不允许使用这个能力的,官方建议使用Beta版本。所以你懂了吧,如果必须要用,就需要你的用户安装正确版本的油猴哦~~

共享数据

如果我们需要跨域名的数据共享,那么使用油猴的GM_*Value相关接口即可,它的命名空间我个人的理解应该是基于脚本的,并不是访问网站的域名。这样我们就可以做到同一个脚本插件下不同的页面灵活的传递数据了。
配合GM_addValueChangeListener监听目标变量的状态改变事件,可以实现更多炫酷的想法哦。

复杂交互

假如只是不爽源网站的界面,那借助油猴你可以大刀阔斧的进行一番装修,直到满意为止~~
或者仅仅是想提供一个额外的按钮,点击后做点什么羞羞的事儿,那也不是什么难事儿~~
但如果你想要的是,“接管”用户的操作,让网站自动的进行一系列的操作(例如:在电商系统里,自动的完成将一系列的目标商品批量加入购物车),那你可就要停下来思考一下了。

没错,问题在于:浏览器刷新
你写的油猴脚本载入并执行,是在每次浏览器加载页面后的指定事件发生时触发的。假如前面提到的这一系列的操作,会触发浏览器重新载入页面,那你的油猴脚本其实也会一并重新加载(即执行上下文重置)。
那每次刷新,脚本怎么知道要如何“继续”执行合适的操作呢?

这个时候,我们就还是要借助GM_*Value相关接口了,思路是这样的:把这一系列的操作,分解成一段一段的,每一段的最后一步一定要确保触发页面加载
然后,我们只需要将拆分后得到的全部的可执行命令保存在GM_VALUE里,另一方面在脚本里监控目标变量是否有内容,有的话就优先开始按顺序取出指令进行执行即可(执行完记得删除哦)。

大概的代码如下:

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
31
32
33
34
35
36
37
38
39
40
41
42
   function createStep(){  //用来生成可执行命令集合。
let steps = [{cmd:'clearCart'},
{cmd:'searchSKU', data: 'kazaff'},
{cmd:'keyinQTY', data: 7},
{cmd: "pageRefresh"},
{cmd:'over'}
];

GM_setValue('autoRun', steps);
}


// 脚本加载完毕后会自动触发
(function autoRun(){
let steps = GM_getValue('autoRun', null);
if(steps == null || steps.length == 0){
return;
}

let currentStep = steps.shift();
GM_setValue('autoRun', steps);
switch(currentStep.cmd){
case "clearCart":
clearCart();break;
case "searchSKU":
searchSKU(currentStep.data);break;
case "keyinQTY":
keyinQTY(currentStep.data);break;
case "pageRefresh":
window.location.reload();break;
case "over":
GM_deleteValue('autoRun');
alert("购物车导入完毕");
}
}());


// 在页面上植入触发按钮
jQuery('目标DOM').prepend('<button id="autoRun">自动加满购物车</button>');
jQuery('#autoRun').click(function(){
createStep();
});

参考资料

油猴脚本开发入门
GM_cookie - HttpOnly Cookie #465

Author: kazaff
Link: https://blog.kazaff.me/2021/04/04/这只猴子有点油/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
微信打赏
支付宝打赏