油猴脚本开发指南

· · 个人记录

博客阅读体验更佳

目录: 暂无

《NOI》是由€€£自主研发的一款全新开放世界冒险游戏。游戏发生在一个一个被称作「机房」的幻想世界,在这里,被神选中的仙贝将被授予「C++」,引导蒟蒻之力,在美妙的学习中寻找摸鱼的真谛和€€£失散的木琴——同时,逐步发掘「草」元素的真相。

发现问题

ciallo~这里是cjyx9捏,瓦达西在使用ybtoj时经常会被其朴实の外观还有伤眼睛的字体戳瞎呢,呐呐,真的是红豆泥麻烦呢,所以瓦达西决定进行⭐彻⭐底⭐的⭐调♂教。(呕

技术栈

找寻其需要的技术栈并不难,我们要实现的其实就是和exlg一样的效果,exlg用什么技术,基本我们就用什么,差不了多少。

extend-luogu/extend-luogu: 大型网络游戏服务器加强插件,增添各种炫酷魔法。 (github.com)

分析技术栈:

方案设计

由于题目页面我使用的最多,这里首先简单设想了一下题目展示页的改造点,并不全面。

着手代码

准备工作

目录结构

exlg这个项目是工程化的,包括 CI,CD,规范化,组件化,模块化,构建等等。需要一定的 Node 和一些构建工具的基础,光看这目录结构就不是我们现在能学的。 所以,我们暂时采用简单目录结构编写项目。

新建文件夹,目录结构如下(一个完整项目必须拥有好的目录结构才会显得清晰可拓展,单文件在巨大项目中是不可取的):

ybt_style/

编辑器的选择

给出我的环境:windows11下的VScode,使用插件:live server、auto close tag、color highlight、Path Intellisense、chatgpt,主题:Material Theme High Contrast,字体:Jetbrains Mono。

其中,liveserver个人认为比较重要(实时刷新网页,解放双手)。

翻日报时看到很多推荐vsc写c++的,个人认为vsc在写竞赛c++(单文件)的表现不如dev和ouuan大佬的cpeditor,体现在体积大,配置杂,调试难,与其折腾这个好看的vsc,不如老老实实dev。vsc更适合的是python和Js等开发,各种插件用着也很省心,另:别在环境上费太大时间。

有关git

如果脚本只是自己写给自己用,那git无关紧要。 如果需要多人一起写或给很多人用,git还是要提一下。有关git用法自行百度,这里讲一些点:

  1. 回答一下本应是目录结构的问题,油猴插件会自动识别直链中类似xx.xx.user.js的js文件为油猴脚本,所以以userscript.user.js命名
  2. github raw日常在GFW那边,我们可以使用cdn方便用户获取脚本,见官方示例
// load any GitHub release, commit, or branch
// note: we recommend using npm for projects that support it
https://cdn.jsdelivr.net/gh/user/repo@version/file

// load jQuery v3.2.1
https://cdn.jsdelivr.net/gh/jquery/[email protected]/dist/jquery.min.js

所以我的脚本放在 github.com/nick-cjyx9/fxxkybt 那么cdn加速就在 https://cdn.jsdelivr.net/gh/nick-cjyx9/fxxkybt/userscript.user.js

入门:Hello World!

首先要明确油猴的大概原理:其实就是向网页加入一段自己的js代码以此改变网页内容,实现自动操作等。(只是方便理解,油猴早就抛弃了这种不安全的做法) 我们要模拟向网页插入我们的脚本,只需要在源码底部加入

<script src="problemshow.js"></script>

我们在problemshow.js里加入以下代码后,打开live server。

alert("hello world!");

此时如果浏览器中如下输出,ybt页面基本无误,恭喜你,已经入门了脚本开发(雾。

实际功能的开发

个人开发者在开发脚本时,往往优先开发自己想要的功能(?,所以综合考虑,我选择先做复制按钮。

Copy it!

  1. 最终效果:

  2. 将按钮插入到网页中: 经过f12观察,我们发现所有样例都位于<pre>标签中,且此标签在网页中只负责放样例,所以我们只要选择所有pre标签遍历逐个添加按钮就行,

problemshow.js

function createCopyBtn() {
    let preTags = document.querySelectorAll("pre"); //选中所有pre标签
    for (let i = 0; i < preTags.length; i++) {
        const preTag = preTags[i];
        let box = preTag.parentElement;
        let holder = document.createElement("div"); //搭载按钮的容器
        holder.innerHTML = `
      <a class="copy" style="
      font-size: .8em;
      float: right;
      margin-right: 18px;">copy</span>
      `; //按钮
      //此处留白给复制功能
       box.appendChild(holder); //添加按钮
    }
}

(function () {
    'use strict';
    createCopyBtn();
})();

运行此代码,可以看到按钮被添加在文本框下。接下来添加点击事件,

  1. 点击事件:

作为一个Google-Oriented Programmer,我去百度找了一段代码 ^1,直接套用是不行的,因为@click是vue的写法,我们对它稍作修改

holder.onclick = function () {
    //监听按钮按下事件
    const input = document.createElement('input') // 创建input对象
    input.value = preTag.innerText // 设置复制内容
    document.body.appendChild(input) // 添加临时实例
    input.select() // 选择实例内容
    document.execCommand('Copy') // 执行复制
    document.body.removeChild(input) // 删除临时实例
    truebtn = holder.children[0];
    truebtn.innerText = 'copied!';
    setTimeout(() => truebtn.innerText = 'copy', 1000);
    //设计一个copied效果提示用户
}

这样就成了,在测试时,我们又发现,它不能复制多行内容

  1. 修第一个bug—善用搜索引擎: 这是我们遇到的第一个bug,由于我们还不具备独自修改的能力,故百度 ^2 得知// 使用textarea支持换行,使用input不支持换行于是将创建input对象改为textarea,问题解决。

注: