试着写了个油猴脚本,但是时灵时不灵

试着写了个油猴脚本,哔哩哔哩播放多part视频时,在标题中显示当前是第几part,当前part的名字。主要功能已经实现,但是时灵时不灵(发生问题时脚本根本不加载)。

试过多种等待页面完成加载的方法似乎都不行,干脆加了个延时,发现只在第一次打开页面时正常,自动播放下一part或者手动点下一part,都不生效。

请坛友康康怎么破?此处@dms

代码如下

// ==UserScript==
// @name         Bilibili分P标题
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  从列表中抽取Bilibili分P视频中当前part的标题,并写入到标题中
// @author       tumuyan
// @match        https://www.bilibili.com/video/*
// @icon         https://www.google.com/s2/favicons?domain=bilibili.com
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    setTimeout(function () {
        var searchStr = location.search;
        var t=0;

        if(searchStr.length>1){
            t= Number(searchStr.replace(/.*(\?|&)p=([0-9]+)(&.*|$)/,"$2"))-1;
        }

        console.log("bili分p p="+t);

        var p= document.getElementsByClassName("list-box")[0];
        var l=p.childNodes[t];

        console.log("bili分p list-box.html="+l.innerHTML);

        if(l!=null){

            let h=document.getElementsByTagName("h1")[0];
            let m=h.innerText+" / "+l.innerText.replace(/[\s0-9:]+$/,'');

            console.log("bilibili分P = "+m);
            h.textContent=m;
            let n=document.getElementsByTagName("title")[0];
            n.textContent=m+" - 哔哩哔哩_bilibili";

        }

    },3000)

})();

百度了个监控dom变化的方法,修改后正常了。这是成品

因为跳转的时候并没有刷新页面,所以脚本也没有被重载。

在打开这个页面的时候,脚本已经运行过了,后面的跳转又没有刷新,所以脚本自然不会再运行。

这种处理起来比较麻烦,我现在是加几个事件监听器,然后再对事件进行具体判断(因为当页面载入完成的时候,也有可能触发相应的事件

var mz = location.href;
let glt=1000;
var inq = setInterval(function () {
if (mz != location.href) {
clearInterval(inq);
ks();
}
}, glt);

在你的主函数里加个循环,不停检测当前网址就行了,ks() 换成你要触发的函数。

如果连网址都没改变,就监测个会改变的 dom 的innerText ,也一样

不停检测网址也是个办法,但是感觉有点浪费资源。百度了个监控dom变化的方法,解决问题了。

把 setTimeout 改成 setInterval,每隔几秒都做一次咯。

设置计时器的方法可行,但不优雅。计时器的判断如果设置得好,其实资源占用并不高,但是难以做到即时响应,如果想要提高响应速度,就必然会提高资源占用,因为循环的频率增加了。即便设置为一毫秒执行一次,在实际运行中并不会达到这么高的频率,所以可以认为这种方法的响应必然存在延迟。

而监听事件则可以在事件发生的第一时间触发。

相关知识点:HTML5 的 history API。

当活动历史记录条目更改时,将触发 popstate 事件

const handler = /* 你要执行的函数 */
window.addEventListener('popstate', handler)

这样添加一个监听器,当事件发生变化时执行对应的函数。

但仅这样操作还会面临两个问题:

history.pushState()history.replaceState() 不会触发 popstate 事件。

而这两种方法正是网页中最常用的,所以要为他们也添加监听器。下面是一种比较常见的添加监听器的方法。

const addHistoryEvent = function(type) {
    var originalMethod = history[type];
    return function() {
        var recallMethod = originalMethod.apply(this, arguments);
        var e = new Event(type);
        e.arguments = arguments;
        window.dispatchEvent(e);
        return recallMethod;
    };
};
history.pushState = addHistoryEvent('pushState');
history.replaceState = addHistoryEvent('replaceState');

const handler = /* 你要执行的函数 */
window.addEventListener('pushState', handler);
window.addEventListener('replaceState', handler);

页面加载时 Chrome 和 Safari 通常会触发 (emit ) popstate 事件

就是说在页面刚刚加载完成时也会触发一次 popstate 事件,但这又不是普遍的必然现象,处理起来就比较尴尬,所以我的做法是,对这个事件,判断一下网址是否发生改变。

这个操作很简单,就不写示例代码了。

hashchange

但是还有一种另外的情况,就是对于网址的改变并没有使用上述方法,而是借用了网址中的锚点,就是井号后面的内容。这部分在网址中被称作为 hash。hashchange 这个事件就是在 hash 发生变化时被触发。

所以有必要的话,也可以为他添加一个监听器,具体方法和第 1 条示例代码一样。

(然后欢迎小可爱们用微信扫描下面小程序码)

Coffee