Protogalaxy

Planet #0

Csgopolygon Withdraw Assistant扫货插件开发日志

Github: https://github.com/SolitudeRA/CSGOPolygon-withdraw-assistant

最近GO群里的大商又有了新需求,因为需要在赌狗网站上扫货,并且货物信息一直在变,而且竞争激烈,所以又找到了我,要做一个能显示每次刷新之后新出来的货物的Chrome插件。虽然最近比较忙,不过在一番准备之后,历经半个月,终于是拿出了一个基本能用的0.9Beta版,期间踩了很多坑,并且还有不少未解决的奇怪问题,所以写篇日志,整理如下:

首先,由于网站本身需要先经过Google的人机验证才能将货物页面刷新出来,所以为了节省系统资源与减少未知的错误,还是使用了与上一个插件相同的被动监听策略,也就是Mutation Observer。不过,有一点不同的是,因为创建了新的div来存放新出现的货物,导致原来在货物div的绑定的监听事件全部失效,并且货物要可以在不同div之间来回移动,所以需要动态绑定click事件到新添加的元素上。为了实现这一点,我用到了Mutation Observer的另外一个特性–Mutation Record。简单来说,Mutation Record可以作为第一个参数来传递给Mutation Observer的回调函数,用来记录发生在观察对象上的DOM变化。通过调用Mutation Record的addedNodes属性,可以获得DOM行为中被添加的DOM对象,这使得我可以动态的为对象绑定click事件。不过,第一个坑就在这里,我原以为每次传给回调函数的是一个单一的Mutation Record对象,DOM树每改变一次就触发一次,其中包含着每次DOM变动的记录,结果与我预想的不同,Mutation Observer的回调函数是在所有DOM变动完成后才触发,并且返回的是一个Mutation Record数组,数组长度与变动次数相符。不过这个坑比较浅,多用几次console.log()来观察就可以避过这个坑,完成版函数如下:

let observerRight    = new MutationObserver(function (mutationRecord) {
    let addedNode = mutationRecord[1].addedNodes[0];
    if ($(addedNode).hasClass("slot-right-ext")) {
        $(addedNode).on("click", function () {
            let parent  = $(this).parent();
            let pointer = $("#right-ext-reals").children("[data-pos='" + $(this).attr("data-pos") + "']");
            pointer.prepend(this);
            parent.remove();
            addPadding("#right", 4);
        });
    }
});

第二个坑也比较浅,由于需要通过比对两次刷新出来的货物列表来确定新出现的货物,所以用到了ES6语法的新特性,也就是Map对象,通过Map对象的遍历接口与自带的方法,可以方便的实现建立Map并且互相比对的操作。因为两次比对之间需要涉及到刷新页面,所以需要通过SessionStorage来存储来实现Map的持久化。这时,坑来了,SessionStorage存储的value必须为字符串类型,所以在进行存储时必须将Map进行类型装换,基本解决方法是将Map内数据转换为JSON字符串进行存储。但是,作为ES6新特性的Map对象,JSON自带的序列化方法stringify() 无法将其转换。此时就需要将ES6Map对象转化成stringfy()方法能够操作的一般map对象,解决方法如下:

//Map序列化
sessionStorage.setItem("previous", JSON.stringify([...next]));
//将JSON字符串转化成ES6 Map
let previous = new Map(JSON.parse(sessionStorage.getItem("previous")));

以上写法运用到了js的扩展操作符[…],具体用法可参考MDN的相关介绍

第三个坑,也是目前未解决的深坑,就是jQuery的append()方法会造成父元素与目标元素的消失,相关代码如下:

let observerRight    = new MutationObserver(function (mutationRecord) {
    let addedNode = mutationRecord[1].addedNodes[0];
    if ($(addedNode).hasClass("slot-right-ext")) {
        $(addedNode).on("click", function () {
            let parent  = $(this).parent();
            let pointer = $("#right-ext-reals").children("[data-pos='" + $(this).attr("data-pos") + "']");
            pointer.prepend(this);
            parent.remove();
            addPadding("#right", 4);
        });
    }
});

被动监听器会给每个新加入的货物绑定一个click事件,当事件触发时,会将元素移至另一个div中的相关位置。实际操作时,在移动的过程中,目标元素会和其将要移动至的父元素一起消失,目前造成此问题的原因仍然未知。

第四个坑,也是一个深坑_(:з」∠)_。在尝试解决第三个坑的时候,用到了被动监听器。由于原页面会给class为slot的元素统一绑定click事件监听,所以初步设想大概是由于我在移动元素时也绑定了事件监听,可能造成了冲突导致了append操作发生可不可知的错误。具体解决思路是在移动元素时移除class slot,并且使用被动监听器为元素绑定事件监听以避免未知错误,但是在被动监听器的启动的过程中,报了target的类型不是Node的错误,但是选择器并未出错,在更改了选择器的选择方法后仍然报相同的错误,造成这个情况的原因到现在仍然未知。

以上,总算是出了一个能用的beta,但是还是有很多问题,接下来的任务就是问问谷歌爸爸或者在MDN上找一找看看有没有这些问题的解决办法了。

 

 

发表评论