【问题标题】:How to run a script every time a new page is loaded on YouTube?每次在 YouTube 上加载新页面时如何运行脚本?
【发布时间】:2014-02-03 01:44:46
【问题描述】:

从去年的某个时候开始,YouTube 就让每个页面实际上并没有加载一个全新的页面,而主要只是重新加载 div#content 中的内容。当您单击 YouTube 中的链接并看到页面顶部的红色加载栏时,您会注意到这一点。

我有一个修改 YouTube 上元素的 Greasemonkey 脚本,但现在 YouTube 不会重新加载整个页面,Greasemonkey 脚本不再在每个“新”页面上触发。如何让 Greasemonkey 脚本在我加载到 YouTube 上的每个“新”页面上触发?

我在这个 Greasemonkey 脚本中使用 jQuery。我尝试使用 .on()DOMNodeInserted 之类的函数,但我找不到正确的组合使其正常工作。使用我一直在使用的事件监听器,我最终会为每次页面加载运行我的脚本数百次,例如:

$('div#page').on('DOMNodeInserted', 'div#content', function() { });

我正在考虑的另一个解决方案是让 YouTube 上的所有链接都像正常一样加载页面,而不是他们这样做的新方式。

【问题讨论】:

  • 将事件监听器附加到 div#content。
  • @Mike:这是一个不错的答案,如果你提供一个简短的代码示例
  • 是的,我正在寻找一些示例代码。我知道我需要一个事件监听器,但我找不到合适的“组合”来让它在 YouTube 上正常工作。我以前在其他网站上做过,但 YouTube 似乎有点不同。
  • div 没有更改事件,因此您最好的解决方案似乎是使用间隔来检查内容是否已更改。 Here's some code someone else wrote, I'm not reinventing the wheel on this one.
  • 是否也可以只关注网址更改?可能是这样的stackoverflow.com/questions/2161906/…

标签: javascript jquery html youtube greasemonkey


【解决方案1】:

经过一番研究,我自己弄清楚了。首先,我不喜欢使用setTimeout 的解决方案。例如,这通常是一种优于已弃用的DOMNodeInserted 的方法(我在一些脚本中使用,但尽量避免),但如果可能,我总是更喜欢脚本实际执行的解决方案在特定事件之后。我已经发布了我最初在下面第一部分中使用的解决方案,然后是我在第二部分中使用的最终解决方案。 以下所有代码都需要 jQuery。

不错的解决方案,但不是最好的

起初,我有一个解决方案,我向所有 A 元素添加了一个 click 事件,这将运行一个计时器,该计时器会在 2 秒后运行我的脚本。这并不优雅,因为如果页面加载很快,那么脚本没有运行的瞬间。如果页面加载超过两秒钟,则脚本根本不会运行。脚本如下:

$('a').click(function()
{
    setTimeout(youtubeFunction, 2000);
});

更好的解决方案

所以我开始寻找与我想要完成的目标相关的解决方案。我最终找到了与我有类似问题的其他人(例如想要创建修改 YouTube 页面的 Chrome 脚本的人)。这让我找到了this particular Stack Overflow solution,它基本上说YouTube页面顶部的红色加载栏是一个CSS过渡元素,它在完成时创建了一个transitionend(区分大小写)事件。链接解决方案中的代码并不完整(无论如何对我来说),但它确实解释了如何实现工作解决方案。我的代码每页只运行一次,非常完美。这就是我现在所拥有的:

function youtubePageChange()
{
    youtubeFunction();
    $('body').on('transitionend', function(event)
    {
        if (event.target.id != 'progress') return false;
        youtubeFunction();
    });
}

$(youtubePageChange);

为了解释上面的代码,基本上我会在您第一次加载 YouTube 页面时运行一次代码(例如通过在地址栏中输入 URL)。然后对于需要进度条的每次后续点击,代码都会再次运行。

红色进度条码

哦,为了以后参考,当红色进度条出现在 YouTube 页面顶部时,网站会在BODY 的末尾临时添加一个新的DIV,代码如下:

<div id="progress" class="waiting" style="transition-duration: 400ms; width: 99%;"><dt></dt><dd></dd></div>

【讨论】:

  • 我现在遇到了问题。它只工作了一半的时间。 YouTube 一定改变了一些东西,我现在无法确定它是什么。我现在刚刚恢复到setInterval,作为后备。
  • 这里也一样。大部分时间都有效,但并非一直有效
【解决方案2】:

挂钩到 popstate 可能是一个选项,但由于某种原因我无法使其正常工作(youtube 可能阻止它传播),所以我想出了这个显示概念:

var currentState = "";
setInterval(function(){
    if (currentState != history.state["spf-referer"]) {
        currentState = history.state["spf-referer"];
        console.log("Do Stuff!");
    }
},250)

只需观察 history.state 的变化,此时它就会记录下来。状态应该在 url 更改时随时更改,即使不是由于页面重新加载。

【讨论】:

  • 我可以使用hashchange 事件吗?虽然我只是尝试过,但它似乎不起作用,但也许类似的东西可能会奏效。
  • 不,因为哈希没有改变。正确的事件是 popState 事件,但就像我说的那样,我无法让它与 youtube 一起使用。他们可能会阻止它。
  • 当用户观看长视频时,这会占用大量内存。一个小时的视频会产生 14400 次循环浪费检查。
【解决方案3】:

您可以设置一个在页面完成加载时调用的侦听器。

这是针对新的 YouTube 材料设计的:

body.addEventListener("yt-navigate-finish", function() {
    //your code
});

这是给老人的:

window.addEventListener("spfdone", function() {
    //your code
});

(如果您使用*monkey,则需要使用unsafeWindow

请记住,旧设计将被停用,因此您的脚本在此之后可能无法运行。

【讨论】:

    猜你喜欢
    • 2019-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-10
    相关资源
    最近更新 更多