我已经构建了一个Chrome扩展程序,可以在初始页面加载时故意隐藏缩略图,并且效果很好。但它也隐藏了#34;加载更多"单击一次后按钮,可防止加载更多缩略图,即使还有更多视频/缩略图需要加载。
以下是点击加载更多后执行的扩展程序代码部分,然后隐藏加载更多按钮:
var insertedNodes = [];
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
// loop through each chunk of html that changes on the page
for (var i = 0; i < mutation.addedNodes.length; i++){
newHTMLChunk = mutation.addedNodes[i];
if (!newHTMLChunk.tagName)
continue;
qHTML = $('<div/>').html(newHTMLChunk).contents();
var vID = qHTML.find('div').attr("data-context-item-id");
if(vID){
console.log("dynamic vID: " + vID);
qHTML.find('img').hide();
}
}
})
});
observer.observe(document, {
attributes: true,
childList: true,
characterData: true,
subtree:true
});
以下是YouTube的加载更多按钮的html,它似乎没有任何与img选择器匹配的隐藏内容:
<span class="yt-uix-button-content">
<span class="load-more-loading hid">
<span class="yt-spinner">
<span class="yt-spinner-img yt-sprite" title="Loading icon"></span>
Loading...
</span>
</span>
<span class="load-more-text">
Load more
</span>
</span>
以下是newHTMLChunk.innerHTML
内容的一个示例(请注意,只有1个img元素,而这是我要隐藏的那个,而不会隐藏“加载更多”按钮并且不会阻止更多的拇指加载):
<div class="yt-lockup clearfix yt-lockup-video yt-lockup-grid vve-check" data-context-item-id="n3Qb30awpLs" data-visibility-tracking="QLvJwrX0-4a6nwE=">
<div class="yt-lockup-dismissable">
<div class="yt-lockup-thumbnail">
<span class=" spf-link ux-thumb-wrap contains-addto">
<a href="/watch?v=n3Qb30awpLs" class="yt-uix-sessionlink" aria-hidden="true" data-sessionlink="ei=PdyEWNiaGozB-AOT64qQCA&feature=c4-videos-u">
<span class="video-thumb yt-thumb yt-thumb-196">
<span class="yt-thumb-default">
<span class="yt-thumb-clip">
<img onload=";__ytRIL(this)" alt="" aria-hidden="true" width="196" src="https://i.ytimg.com/vi/n3Qb30awpLs/hqdefault.jpg?custom=true&w=336&…amp;jpg444=true&jpgq=90&sp=68&sigh=CiLl7jzBOIIFewRt-KAOEs-bKwA" data-ytimg="1">
<span class="vertical-align"></span>
</span>
</span>
</span>
</a>
<span class="video-time" aria-hidden="true">
<span aria-label="103 seconds">1:43</span>
</span>
<span class="thumb-menu dark-overflow-action-menu video-actions">
<button class="yt-uix-button-reverse flip addto-watch-queue-menu spf-nolink hide-until-delayloaded yt-uix-button yt-uix-button-dark-overflow-action-menu yt-uix-button-size-default yt-uix-button-has-icon no-icon-markup yt-uix-button-empty" type="button" aria-haspopup="true" aria-expanded="false" onclick=";return false;">
<span class="yt-uix-button-arrow yt-sprite"></span>
<ul class="watch-queue-thumb-menu yt-uix-button-menu yt-uix-button-menu-dark-overflow-action-menu hid">
<li role="menuitem" class="overflow-menu-choice addto-watch-queue-menu-choice addto-watch-queue-play-next yt-uix-button-menu-item" data-action="play-next" onclick=";return false;" data-video-ids="n3Qb30awpLs">
<span class="addto-watch-queue-menu-text">Play next</span>
</li>
<li role="menuitem" class="overflow-menu-choice addto-watch-queue-menu-choice addto-watch-queue-play-now yt-uix-button-menu-item" data-action="play-now" onclick=";return false;" data-video-ids="n3Qb30awpLs">
<span class="addto-watch-queue-menu-text">Play now</span>
</li>
</ul>
</button>
</span>
<button class="yt-uix-button yt-uix-button-size-small yt-uix-button-default yt-uix-button-empty yt-uix-button-has-icon no-icon-markup addto-button video-actions spf-nolink hide-until-delayloaded addto-watch-later-button yt-uix-tooltip" type="button" onclick=";return false;" role="button" title="Watch Later" data-video-ids="n3Qb30awpLs"></button>
<button class="yt-uix-button yt-uix-button-size-small yt-uix-button-default yt-uix-button-empty yt-uix-button-has-icon no-icon-markup addto-button addto-queue-button video-actions spf-nolink hide-until-delayloaded addto-tv-queue-button yt-uix-tooltip" type="button" onclick=";return false;" title="Queue" data-video-ids="n3Qb30awpLs" data-style="tv-queue"></button>
</span>
</div>
<div class="yt-lockup-content">
<h3 class="yt-lockup-title ">
<a class="yt-uix-sessionlink yt-uix-tile-link spf-link yt-ui-ellipsis yt-ui-ellipsis-2" dir="ltr" title="Josh’s Afterlife Analogy" aria-describedby="description-id-407587" data-sessionlink="ei=PdyEWNiaGozB-AOT64qQCA&feature=c4-videos-u" href="/watch?v=n3Qb30awpLs">Josh’s Afterlife Analogy</a>
<span class="accessible-description" id="description-id-407587"> - Duration: 103 seconds.</span>
</h3>
<div class="yt-lockup-meta">
<ul class="yt-lockup-meta-info">
<li>16,475 views</li>
<li>2 months ago</li>
</ul>
</div>
</div>
</div>
<div class="yt-lockup-notifications-container hid" style="height:110px"></div>
</div>
当我逐步浏览Chrome调试器中的代码时,我发现每个新加载的缩略图周围的整个div都被隐藏,而不仅仅是图像。所以,事实上,额外的拇指正在加载,但随后整个div被隐藏(不仅仅是img元素),并且所有后续的div一个接一个地向左滑动,直到看起来没有任何新的加载。即使该按钮中没有图像,最后的div hide也会隐藏按钮。为什么要这样做?
如何更改此设置以便(1)其他视频缩略图按预期加载和显示,并且只隐藏内部的img元素; (2)Load more
按钮保持可见,直到真正没有更多的拇指加载?
答案 0 :(得分:1)
MutationObserver回调最可能的问题是jQuery .html(DOMnode)
方法将提供的DOMnode从页面文档移动到分离的(非呈现的)节点qHTML
。
另外,MutationObserver回调必须非常快,以免减慢页面加载速度
见Performance of MutationObserver to detect nodes in entire DOM。
也就是说,仅在您想要的元素上使用jQuery,而不是在每个添加的节点上使用。
onElementAdded('div[data-context-item-id]', document, function(elements) {
elements.forEach(function(element) {
var vID = element.dataset.contextItemId;
if (vID) {
console.log("dynamic vID: " + vID);
$(element).find('img').hide();
}
});
});
function onElementAdded(selector, baseNode, callback) {
new MutationObserver(function(mutations) {
var found = [];
for (var mutation, i = 0; (mutation = mutations[i++]); ) {
var addedNodes = mutation.addedNodes[i];
for (var node, j = 0; (node = addedNodes[j++]); ) {
// skip non-element nodes
if (!node.tagName) {
continue;
}
// does the added node itself match the selector?
if (node.matches(selector)) {
found.push(node);
continue;
}
// does the added node contain child elements matching the selector?
// (since qS is much faster than qSA it makes sense to use it first)
if (node.querySelector(selector)) {
var children = node.querySelectorAll(selector);
// prevent stack overflow
if (children.length < 1000) {
Array.prototype.push.apply(found, children);
} else {
found = found.concat(children);
}
}
}
}
if (found.length) {
callback(found);
}
}).observe(baseNode || document, {
childList: true,
subtree: true,
});
}
FWIW,如果目标只是使用data-context-item-id属性将图像隐藏在div元素中,那么您可以使用简单的一次性CSS样式注入(在manifest.json中或通过手动执行)添加<style>
元素):div[data-context-item-id] img { display: none; }
答案 1 :(得分:0)
我用以下内容解决了这个问题,并得到了wOxxOm评论的帮助(但不是发布的答案)。它现在完美地工作,至少在某种程度上更有效。 wOxxOm,我赞成你的回答,我仍然欢迎你的任何评论。我尝试了你的.observe()更改,它似乎没有用,但我可能做错了。
var insertedNodes = [];
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
// loop through each chunk of html that changes on the page
for (var i = 0; i < mutation.addedNodes.length; i++){
newHTMLChunk = mutation.addedNodes[i];
if (!newHTMLChunk.tagName)
continue;
if(newHTMLChunk.getElementsByTagName('div').length > 0){
if(newHTMLChunk.getElementsByTagName('div')[0]){
var vID = newHTMLChunk.getElementsByTagName('div')[0].getAttribute('data-context-item-id');
if(vID){
$("div[data-context-item-id='" + vID + "'] img").hide();
}
}
}
}
})
});
observer.observe(document, {
attributes: true,
childList: true,
characterData: true,
subtree:true
});