如何使我的用户脚本在使用历史记录 API 的网站的特定页面上工作
How to make my userscript work on specific pages of a site that uses the history api?
(这是本讨论的延续)
我一直在尝试制作一个脚本(用于 instagram),以显示查看个人资料页面(示例个人资料)时当前可见的总共有多少张图片。它在屏幕右上角显示计数器,并支持无限滚动。
在这里:
// ==UserScript==
// @name Instagram - visible images counter
// @name Instagram - visible images counter
// @include https://instagram.com/*
// @grant none
// ==/UserScript==
var p = document.getElementsByClassName('-cx-PRIVATE-PostsGridItem__root');
var m = document.getElementsByClassName('-cx-PRIVATE-PostsStatistic__count');
var ww = m[0].innerHTML.replace(/('d+),(?='d{3}('D|$))/g, "$1"); // Regex to strip the thousand comma seperator from the posts number
var z = (p.length/ww)*100;
var counter = p.length+' / '+m[0].innerHTML +' that is ' +z.toFixed(1) + '%';
var div = document.createElement("div");
div.style.top = "1px";
div.style.right = "1px";
div.style.position = "fixed";
document.body.appendChild(div);
div.id="mycounter";
mycounter = document.getElementById('mycounter');
mycounter.innerHTML = counter;
mycounter.style.top = "1px";
mycounter.style.right = "1px";
mycounter.style.position = "fixed";
/// ---------------------------------
/// mutation observer -monitors the Posts grid for infinite scrolling event-
/// ---------------------------------
var target1 = document.querySelector('.-cx-PRIVATE-PostsGrid__root');
var observer1 = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
p=document.getElementsByClassName('-cx-PRIVATE-PostsGridItem__root');
m = document.getElementsByClassName('-cx-PRIVATE-PostsStatistic__count');
ww = m[0].innerHTML.replace(/('d+),(?='d{3}('D|$))/g, "$1");
z = (p.length/ww)*100;
counter = p.length+' / '+m[0].innerHTML +' that is ' +z.toFixed(1) + '%';
mycounter.innerHTML = counter;
});
})
var config = { attributes: true, childList: true, characterData: true }
observer1.observe(target1, config);
我的脚本工作正常,但我有这个问题:
Instagram,在最近重新设计之后 - 我认为 - 似乎使用单页应用程序工作流程,
即获取点击的链接内容并用它替换当前页面,然后更改浏览器的当前 URL,所有这些都无需实际重新加载页面。
因此,我的脚本仅在新选项卡中打开配置文件 URL 时才有效。
在我的时间线(https://instagram.com)中在同一选项卡中打开配置文件URL时,它不起作用。
换句话说,它不起作用(在我打开 https://instagram.com 并登录后)
如果我单击以查看我关注的用户的个人资料 URL,例如。https://instagram.com/instagram/
我该如何解决这个问题?
有人善意地建议了这 3 种方法:
- 尝试为Instagram网站触发的某些事件
event handler
,例如 例如,GitHub上的pjax:end。- 使用等待特定于配置文件的 html 元素的
mutation observer
。- 或者使用
。setInterval
定期检查 location.href
所以,我一直在尝试各种方法(包括建议#2和#3),但没有成功。
(关于建议#1:我找不到任何类似于pjax:end
的元素)。
所以,到目前为止我尝试过:
(基于建议#2)添加另一个
mutation observer
来检查显示"帖子计数"元素的元素是否存在,如果是,则运行我的代码。var target0 = document.querySelector('.-cx-PRIVATE-PostsStatistic__count'); var observer0 = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { myCode(); }); }) var config0 = { attributes: true, childList: true, characterData: true } observer0.observe(target0, config0);
(基于建议#3)每1秒
location.href
检查一次当前位置是否是配置文件(即不是时间线(https://instagram.com/)。如果为 true,则清除周期函数并运行我以前的代码。var interval = setInterval(testHref() , 1000); function testHref(){ if (location.href != "https://instagram.com/") clearInterval(interval); myCode(); }
只需在我的代码上添加 1 秒的延迟(并将@require规则更改为仅适用于配置文件 URL
// @include https://instagram.com/*/
),但没有成功:setTimeout(function() { }, 1000);
我甚至尝试使用waitForKeyElements实用程序函数,它可以检测和处理AJAXed内容。
我认为以这种方式实现要容易得多,就像一个简单的"等到元素存在"一样工作(我只是使用主配置文件图片作为选择器来等待,因为我找不到任何相关的 AJAX 选择器。此外,我没有在我的代码中使用jNode)。
所以我只是将我的整个代码包含在一个函数visibleCounter
中,并添加了一个 waitForKeyElements 行(见下文),但不幸的是它也不起作用:waitForKeyElements (".-cx-PRIVATE-ProfilePage__avatar", visibleCounter); function visibleCounter(jNode){ myCode() }
我使用 arrive.js 库解决了这个问题。它提供了监视 DOM 元素创建和删除的事件。它在内部使用突变观察器。该库不依赖于jQuery,您可以将以下示例中的jQuery元素替换为纯javascript元素,它可以正常工作。
我引用其作者的这条评论:
我一直觉得 MutationObserver api 有点复杂,所以我构建了一个 库,到达.js,以提供更简单的 API 来侦听元素 创建/删除。
以及它的两种用途:
注意元素创建:
使用 到达事件监视元素创建:
// watch for creation of an element which satisfies the selector ".test-elem" $(document).arrive(".test-elem", function() { // 'this' refers to the newly created element var $newElem = $(this); });
和
注意元素去除
使用 leave 事件监视元素删除。第一个 离开不得是后代或子选择器,即您不能通过 .page .test-elem,而是通过.test-elem。这是因为 MutationObserver 的 API 中的限制。
// watch for removal of an element which satisfies the selector ".test-elem" $(".container-1").leave(".test-elem", function() { var $removedElem = $(this); }); [1]: https://github.com/uzairfarooq/arrive
而且,这是完整的脚本:
// ==UserScript==
// @name Instagram - visible images counter
// @include https://www.instagram.com/*
// @grant none
// @require https://code.jquery.com/jquery-3.0.0.min.js
// @require https://greasyfork.org/scripts/21927-arrive-js/code/arrivejs.js?version=139586
// ==/UserScript==
function showCounter() {
var visibleCount = $( "a[href*='taken-by']" ).length; // Count of visible images
var totalString = $("span:contains('posts')").eq(1).children().eq(0).html(); // The 'total' value (it's a string)
var total = totalString.replace(/('d+),(?='d{3}('D|$))/g, '$1'); // Apply regex to 'total' string to strip the thousand comma seperator
if (visibleCount > total){
visibleCount = total;
}
var visiblePercent = ((visibleCount / total) * 100).toFixed(1); // Visible images as percentage
var counter = visibleCount + ' / ' + totalString + ' that is ' + visiblePercent + '%';
return counter;
}
function createDiv(){
// Creation of the counter element
document.body.appendChild(div);
div.innerHTML = showCounter(); // Initial display of the counter
div.style.top = '1px';
div.style.right = '1px';
div.style.position = 'fixed';
}
function observer(){
/// ---------------------------------
/// mutation observer -monitors the Posts grid for infinite scrolling event-.
/// ---------------------------------
observer1 = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
div.innerHTML = showCounter(); // In each infinite scrolling event, re-calculate counter
});
}).observe($('article').children().eq(1).children()[0], // target of the observer
{
// attributes: true,
childList: true,
// characterData: true,
}); // config of the observer
}
var div = document.createElement('div'); // global variable
var observer1; // global variable
if (document.URL !== 'https://www.instagram.com/' &&
document.URL.indexOf('https://www.instagram.com/p/') === -1 ){
createDiv();
observer();
}
$(document).arrive('article ._5axto', function() { // 'article .5axto'
createDiv();
observer();
});
$(document).leave('article ._5axto', function() {
div.remove();
observer1.disconnect();
});
从我的回答中复制:
对于类似的用例,我使用MutationObserver并检查了每个mutation.addedNodes
中每个节点的node.baseURI
。
(async function() {
'use strict';
const selector = '.quiz--answered';
const observer = new MutationObserver(mutations => {
if (!mutations.some(mutation => Array.from(mutation.addedNodes).some(node => node.baseURI.includes('/quiz/')))) {
return;
}
const elm = document.querySelector(selector);
if (elm) {
// work with elm
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
})();
- "此网站似乎使用滚动链接定位效果.这可能不能很好地与异步平移一起工作;
- 代理一个网站能够在iframe中进行所见即所得编辑-它是如何工作的
- 使用HTML和任何服务器端语言(PHP,.net,ruby)制作的网站是否可以在每个具有浏览器的设备上工作
- Toggle已停止在我的网站上工作
- 谷歌脚本-从网站论坛解析HTML-并将数据写入工作表
- 我可以'我似乎没有得到我的网站'移动导航开始工作
- JavaScript网站与工作实例
- 如何在node.js的帮助下使用网站在localhost上工作
- 如何使Asp.net网站同时在IE 11(非可比模式)和IE 8中工作
- 缓存以使我的网站离线是't工作
- jsFiddle工作,网站JS不工作
- 代码在 jsfiddle 中工作,但在我的网站上不起作用
- 我的jQuery在JSFiddle中工作,但不能在我的网站上工作!我做错了什么
- CSS 在基于 URL 上工作,但不在网站的其他页面中使用.代码点火器
- JavaScript不能在一个网站上工作,但在另一个网站上很好
- 如何让Jsfiddles在网站上工作
- 如何让旋转木马为drupal网站工作
- 带宽检查与视频网站(工作在手机和平板电脑)
- 如何DownForEveryoneOrJustMe.com和其他类似的网站工作与跨域脚本限制
- 网站工作,但不是在iphone上.XMLHttpRequest()错误