注意:这是my previous one的后续问题。
我决定通过#posts
元素中的扩展程序将帖子显示在信息中心上。现在我的问题是 Tumblr自动删除帖子'滚动内容。
以下是移除前正常帖子的示例:
<li class="post_container" data-pageable="post_110141415125">
<div class="post post_full ..." [...]>
<!-- ... -->
</div>
</li>
同样的帖子,删除后的内容:
<li class="post_container" data-pageable="post_110141415125" style="border-radius: 3px; height: 207px; width: 540px; background-color: rgb(255, 255, 255);">
</li>
由于我的扩展程序将帖子重新定位为 pinterest-like 布局,删除帖子&#39;内容会弄乱整个布局。是否可以阻止Tumblr仪表板删除每个.post
中的DOM元素?
修改
我在内容脚本中添加了removeChild
方法的注入代码:
function addScript(){
var script = document.createElement('script');
script.id = 'newRemoveChildScript'; ///just to find is faster in the code
script.src = chrome.extension.getURL("injectedCode.js");
$($('script')[0]).before(script); ///Script is indeed present, I checked that
}
window.onload = addScript;
接下来我做的是用第二个版本创建injectedCode.js
文件,如下所示:
(function (obj, method) {
function isPost(el) {
return (/^post_\d+$/.test(el.id) && ~el.className.indexOf('post'));
}
obj[method] = (function (obj_method) {
return function (child) {
if (isPost(child)) return child;
return obj_method.apply(this, arguments);
}
}(obj[method]));
}(Element.prototype, 'removeChild'));
当我加载Tumblr-Dashboard时,我可以确认head-element中存在Script-element。该文件也正确链接,因为&#39; removeChild&#39;函数被调用一次。似乎在那里删除了一个脚本元素。
从那时起,该函数再也没有被调用过,我可以看到那些空的&#39;再次发帖。
答案 0 :(得分:13)
免责声明 :完全合法的事情发生在这里,不要惊慌!
你要问的是不是很容易要做的事情,但实际上你可以阻止Tumblr在他们离开视口时滚动时隐藏帖子。更准确地说,一个高级程序员实际上可以操纵任何Tumblr方法使其表现得像他想要的那样,但是,现在,让我们专注于你的问题。
Tumblr删除帖子&#39;使页面更轻的内容,让您继续浏览,而不会因为大量的元素而遇到任何延迟和/或难以滚动。想象一下直接向下滚动一小时:你的破折号会有数千个帖子,你的浏览器可能会因每次滚动时必须移动的东西过多而冻结。
我没有检查和理解Tumblr代码的每一行,因为它全部打包/缩小,并且实际上不可能理解任何方法的单行(除非你在Tumblr,在这种情况下恭喜),但是,基本上,我放了一些DOM breakpoints并且我已经检查了当他们离开视口时删除帖子的代码部分。
Tumblr创造了一些自定义和狡猾的&#34;滚动&#34;这些帖子的活动。每当帖子超出视口的距离时,这些事件都会触发。
现在Tumblr会将一些侦听器附加到这些自定义事件上,并且使用li.post_container
元素上的 DOM断点,您将能够看到这些侦听器驻留在dashboard.js
JavaScript文件中。
更确切地说,删除帖子的代码的确切部分&#39;内容如下:
function j(t,v) { try{ t.removeChild(v) } catch(u){} }
其中t
是li.post_container
而v
是其子级:div#post_[id]
。
这部分代码有什么作用?没有什么特别之处:它确实从其父div#post_[id]
中删除li.post_container
元素。
现在Tumblr必须设置已删除帖子的容器的样式,以便保持#posts
元素的高度,该元素包含所有帖子,否则删除帖子的内容会使页面向下滚动H
像素,其中H是已移除的帖子的高度。
此更改发生在另一个脚本index.js
内,我甚至没有仔细查看它,因为它只是无法阅读:
顺便说一下,这个脚本并不重要,因为我们可以使用简单的CSS来防止样式更改。
现在帖子的内容已被删除&#34;,它看起来像这样:
*为了清楚起见:我添加了文字和墓碑,你实际上并没有看到它们lol
所以,最后,当一个帖子离开视口时,会发生以下变化:
<li class="post_container" [...]>
<div id="post_[id]" class="post post_full ..." [...]>
<!-- post body... -->
</div>
</li>
到此:
<li class="post_container" [...] style="border-radius: 3px; height: Hpx; width: Wpx; background-color: rgb(255, 255, 255);">
</li>
现在我们知道Tumblr在滚动仪表板时的行为,我们可以阻止它删除帖子并将它们设置为,看起来像带有圆形边框的空白色死区。
首先是在关心防止移除柱子之前,我们应该将它们设计成不具有固定高度和宽度的样式,覆盖Tumblr离开视口时应用于它们的样式。
我们可以在页面中注入一些简单的CSS,制定规则!important
以防止内联样式覆盖它们。这是我们添加的CSS:
li.post_container {
height: auto !important;
width: 540px !important;
/* 540px is the default width
* change it to any amount that applies to your layout
*/
}
或者,使用JavaScript,我们可以:
var s = document.createElement('style');
s.textContent = 'li.post_container{height:auto!important;width:540px!important;}';
document.head.appendChild(s);
如果我们不想浪费时间考虑一个好的解决方案,我们可以实现最简单的解决方案,并且,在几行代码中我们可以:
复制removeChild
的{{1}}方法,并将其称为Element.prototype
。
将原来的替换为&#34;过滤&#34;拨打电话,决定删除除帖子以外的任何内容。
这是解决问题的简单而愚蠢的代码:
_removeChild
没有注释的代码长度:5行
您可以检查多个条件:例如,您可以检查帖子是否包含类Element.prototype._removeChild = Element.prototype.removeChild
Element.prototype.removeChild = function(child) {
// Check if the element is a post (e.g. the id looks like "post_123456...")
if (/^post_\d+$/.test(child.id)) {
// If so, stop here by returning the post
// This will make Tumblr believe the post has been removed
return child;
}
// Otherwise the element isn't a post, so we can remove it
return Element.prototype._removeChild.apply(this, arguments);
}
和post
,或者post_full
是否有类parentElement
,等等......它取决于你。
完成此操作的更优雅,更狡猾的方法是&#34;编辑&#34;原始的post_container
方法,使用了一些闭包和更复杂的逻辑。这就是我们要做的事情:
创建一个闭包,我们重新定义Element.prototype.removeChild
方法,添加&#34;过滤器&#34;它的帖子。
在此闭包中,我们将定义我们可以调用Element.prototype.removeChild
的自定义过滤器函数,以过滤要删除的元素。
使用第二个闭包,我们将isPost()
方法重新定义为:
使用之前创建的过滤器功能Element.prototype.removeChild
检查要移除的元素。
如果要删除的元素是帖子,则停止此处,不要将其删除。
否则继续并使用isPost()
方法调用原始Element.prototype.removeChild
方法。
这可能看起来很难,但代码并不难理解,我通过评论来实现它以使其更易于理解,这里是:
.apply
没有注释的代码长度:11行
由于内容脚本在隐藏的,不同的(function (obj, method) {
// This is all wrapped inside a closure
// to make the new removeChild method remember the isPost function
// and maintain all the work invisible to the rest of the code in the page
function isPost(el) {
// Check if the element is a post
// This will return true if el is a post, otherwise false
return (/^post_\d+$/.test(el.id) && ~el.className.indexOf('post'));
}
// Edit the Element.prototype.removeChild assigning to it our own function
obj[method] = (function (obj_method) {
return function (child) {
// This is the function that will be assigned to removeChild
// It is wrapped in a closure to make the check before removing the element
// Check if the element that is going to be removed is a post
if (isPost(child)) return child;
// If so, stop here by returning the post
// This will make Tumblr believe the post has been removed
// Otherwise continue and remove it
return obj_method.apply(this, arguments);
}
}(obj[method]));
}(Element.prototype, 'removeChild'));
对象中工作,因此内容脚本代码无法与页面代码交互,您可以使用。我必须从您的内容脚本直接在页面中注入代码。为此,您需要创建一个window
元素并将其插入页面的<script>
。您可以将要注入的代码存储在新脚本中(让我们将其称为<head>
)并使用injectedCode.js
获取要在chrome.runtime.getURL
src中使用的绝对URL。
重要:您需要将<script>
文件添加到injectedCode.js
中的"web_accessible_resources"
field,以便可以从Tumblr访问该文件,就像这样:
manifest.json
然后,您可以创建一个"web_accessible_resources": ["/injectedCode.js"]
设置<script>
.src
,如下所示:
injectedCode.js
这些只是实现目标的两种方法:防止Tumblr在滚动时隐藏帖子。显然还有很多其他方法可以做到这一点,例如使用MutationObserver
来检查子树修改,删除所有帖子并使用新的个人事件和方法创建一个新容器来模拟Tumblr,插入Tumblr代码并直接编辑它(几乎不可能,也不太合法),等等。
我还想强调一下这样一个事实:这只是一个问题的答案,我不负责错误地使用这些操作会损害您的分机用户。