油猴脚本碰到ajax如何实现无刷新多次执行

本文最后更新于:15 天前

前言


话分两头讲,首先是因为蝴蝶关闭比较久,然后断种比较多,虽然最近IYUU已经开始支持了,但是保种实在是不理想,所以我们希望借鉴其他站点的管理思路,对旧的、断种严重的、续种困难的种子进行清理。

其次眼看着七万多的种子,每次删一个种子要弄好几次,任谁都迷糊。。。所以,决定写个脚本,一页一页弄~

过程


首先按照以往的经验,删除如果要点击好几次我就直接把它的请求拉过来,然后重写点击事件完事了~

// ==UserScript==
// @name         hudbt-delete
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        https://hudbt.hust.edu.cn/torrents.php?inclbookmarked=0&incldead=1&spstate=0&page=*
// @icon         https://www.google.com/s2/favicons?domain=hust.edu.cn
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function() {
	// 首先NP架构下都需要一定权限才会展示删除按钮,所以一般人应该是找不到滴~
    $('#torrents').find('tr:gt(0)').each((index, e)=>{
        var id = $(e).find('a.staff-quick-delete').attr('href').match(/id=(\d+)/)[1];
        // 去除跳转按钮,关掉需要点击好几次的面板直接添加点击事件
        $(e).find('a.staff-quick-delete').attr('href', '').click(function(event){
            event.preventDefault();
            //提交请求并解析返回结果
            var url = `https://hudbt.hust.edu.cn/cake/torrents/delete/${id}.json`;
            GM_xmlhttpRequest({
                "method": "POST",
                "url": url,
                "data": encodeURI('_method=DELETE&data%5BreasonType%5D=0&data%5BreasonDetail%5D='),
                'headers':{
                    "Content-Type": 'application/x-www-form-urlencoded; charset=UTF-8',
                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36"
                },
                "onload": function(res) {
                    var result = JSON.parse(res.responseText);
                    if (result.success) {
                        location.reload();
                    } else {
                        alert('删种失败!!')
                    }
                }
            });
        });
    });
})();

乍一看,没什么毛病,很简单。但是在跑的过程中,遇到了一些bug,蝴蝶上一页下一页用的是ajax,无刷新页面,内容却换了。我们的脚本就第一次执行,后来出来的内容该点击几次还是点击几次。

经过几天的搜索尝试:

window.onhashchange=function(event){
  console.log(event);
}
//或者
window.addEventListener('hashchange',function(event){
   console.log(event);
})

// ==UserScript==
// @name     _Amazon Search, alter results
// @include  http://www.amazon.com/s/*
// @require  http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @require  https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant    GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
    introduced in GM 1.0.   It restores the sandbox.
*/

function addCustomSearchResult (jNode) {
    //***** YOUR CODE HERE *****
    jNode.prepend (
        'Buy my stuff, instead!'
    );
}
waitForKeyElements ("#atfResults", addCustomSearchResult);

上述借鉴下来,都不好使,但是明确了一个想法,就是必须要添加事件监听,捕捉到ajax发生了,然后将删除按钮的点击事件覆盖掉。

猛然间看到一个:document.addEventListener(‘DOMNodeInserted’, function() { alert(‘hi’) }, false); 请注意,该事件将由页面结构中的任何更改触发,因此您必须检查自己是否定位了正确的更改。

直接试了一下,给我一直反复的输出hi。。。不过也证明有用,因为我要做的就是这个,ajax导致页面改变,我就判断页面改变了,执行一次脚本。那么如何判断呢?也就是页面刷新之后的差异是什么呢?

// ==UserScript==
// @name         hudbt-delete
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  try to take over the world!
// @author       tomorrow505
// @match        https://hudbt.hust.edu.cn/torrents.php*
// @icon         https://www.google.com/s2/favicons?domain=hust.edu.cn
// @grant        GM_xmlhttpRequest
// ==/UserScript==

//首先将函数封装起来,每次执行就是把页面删除按钮的点击事件覆盖掉
function add_click_function(){
    $('#torrents').find('tr:gt(0)').each((index, e)=>{
        var id = $(e).find("a.staff-quick-delete").attr('href').match(/id=(\d+)/)[1];
        $(e).find('a.staff-quick-delete').attr('href', '').addClass('select_torrent').click(function(ee){
            ee.preventDefault();
            var url = `https://hudbt.hust.edu.cn/cake/torrents/delete/${id}.json`;
            GM_xmlhttpRequest({
                "method": "POST",
                "url": url,
                "data": encodeURI('_method=DELETE&data%5BreasonType%5D=0&data%5BreasonDetail%5D='),
                'headers':{
                    "Content-Type": 'application/x-www-form-urlencoded; charset=UTF-8',
                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36"
                },
                "onload": function(res) {
                    var result = JSON.parse(res.responseText);
                    if (result.success) {
                        location.reload();
                    } else {
                        alert('删种失败!!')
                    }
                }
            });
        });
    });
}

// 判断什么时候执行?我做了一个设计,就是执行一次我将页面的删除按钮添加一个class,如果没有这个class的元素,我就执行一遍,有了就不执行了。
document.addEventListener('DOMNodeInserted', function() {
    if($('.select_torrent').length == 0){
        add_click_function();
    }
}, false);

衍生需求


一次性点击一个删除仿佛不太够,那么我们需要增加批量删除按钮。往上再写一个版本:

// ==UserScript==
// @name         hudbt-delete
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  try to take over the world!
// @author       tomorrow505
// @match        https://hudbt.hust.edu.cn/torrents.php*
// @icon         https://www.google.com/s2/favicons?domain=hust.edu.cn
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function() {
    
    // 页面增加一列,列首删除按钮可以点击进行删种
    $('#torrents').find('thead').find('tr:first').append(`<th class="unsortable"><a id="delete_torrents">删种</a></th>`);
    $('#delete_torrents').click(function(){
        $('input.select_torrent:checked').each((index, e)=>{
            var torrent_id = $(e).attr('title');
            delete_torrent(torrent_id);
        })
    });
    
    // 封装删种操作,传入参数为种子id
    function delete_torrent(torrent_id) {
        var url = `https://hudbt.hust.edu.cn/cake/torrents/delete/${torrent_id}.json`;
        GM_xmlhttpRequest({
            "method": "POST",
            "url": url,
            "data": encodeURI('_method=DELETE&data%5BreasonType%5D=0&data%5BreasonDetail%5D='),
            'headers':{
                "Content-Type": 'application/x-www-form-urlencoded; charset=UTF-8',
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36"
            },
            "onload": function(res) {
                var result = JSON.parse(res.responseText);
                if (result.success) {
                    // 执行成功之后将种子id对应的行删除掉
                    $(`input[title=${torrent_id}]`).parent().remove();
                    console.log(`种子${torrent_id}已经成功删除!!!`);
                } else {
                    console.log(`种子${torrent_id}删除失败!!!`);
                    console.log(result);
                }
            }
        });

    }
    
    // 每一行的最后一列增加一个复选框,勾选之后点击删除即执行删除操作
    function fireOnNewPage () {
        $('#torrents').find('tr:gt(0)').each((index, e)=>{
            var id = $(e).find('a.staff-quick-delete').attr('href').match(/id=(\d+)/)[1];
            $(e).append(`<input type="checkbox" title=${id} value="yes" class="select_torrent" style="margin-top: 50%;" >`)
        });
    }
    
    // 页面监听,主要针对ajax来的
    document.addEventListener('DOMNodeInserted', function() {
        if($('.select_torrent').length == 0){
            fireOnNewPage();
        }
    }, false);
    
})();

结束语


如此就实现了一个简单的ajax下,油猴无刷新脚本多次执行了,have fun!!!



本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!