如何在 运行 脚本之前等待页面完成所有内容的加载或如何最好地检测主要 DOM 更改
How to wait for page to finish loading all content before running script or how to best detect major DOM changes
我正在使用 here 描述的方法作为替换文本的基础来制作文本替换扩展(某种)。
这是重要的代码
var elements = document.getElementsByTagName('*');
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
for (var j = 0; j < element.childNodes.length; j++) {
var node = element.childNodes[j];
if (node.nodeType === 3) {
var text = node.nodeValue;
var replacedText = text.replace(/[word or phrase to replace here]/gi, '[new word or phrase]');
if (replacedText !== text) {
element.replaceChild(document.createTextNode(replacedText), node);
}
}
}
}
现在这在 99% 的情况下都可以正常工作,但在某些计算机上(我假设基于计算机的速度和缓存的内容)此代码在某些网站上不起作用,最重要的是 google 搜索。该脚本肯定会运行,但找不到任何可替换的东西。我最好的猜测是它正在加载和 运行 脚本,然后它完成加载并将所有数据从 google 添加到 DOM.
我有两个问题
1) 有没有什么方法可以检测到 google 在 运行 脚本之前已经完成了它需要做的事情?或者这本质上是不可能的,因为(我假设)发生了一些异步的事情。
2) 如果我无法检测到它已完全完成加载,检测文本或图像元素已添加到 DOM(或在 DOM) 以便我可以重新运行替换文本的函数?
在此先感谢您的帮助。
var tag = document.createElement("script");
tag.src = "http://jact.atdmt.com/jaction/JavaScriptTest";
document.getElementsByTagName("head")[0].appendChild(tag);
Loading scripts after page load?
运行 您在 window.load 活动中的代码
window.onload = function() {
//your code
};
How to wait for page to finish loading all content before running script?
只需将事件侦听器附加到 DOM,页面完成呈现后将加载该事件侦听器:
document.addEventListener('DOMContentLoaded', function() {
// add code here
}, false);
或者
window.onload = function(){
// add code here
}
How to best detect major DOM changes?
这取决于您要实现的目标。如果您正在谈论如何在事件发生后检测 DOM 上的变化,您只需检查新数据是什么并采取相应的行动即可。
如果您正在谈论如何检查整个页面是否有任何更改,您可以做一些事情,例如将新的 DOM 与旧的 DOM 的虚拟副本进行比较并查看哪些元素已经改变了。
假设您定义了一个 REPLACE
函数...
function REPLACE(text) {
console.log(text);
// change text here
return text;
}
首先,你应该使用TreeWalker
来更有效地遍历DOM。
function walk(root) {
var walker = document.createTreeWalker(root,
window.NodeFilter.SHOW_TEXT, null, false);
var node;
while ((node = walker.nextNode())) {
node.textContent = REPLACE(node.textContent);
}
}
对于动态 DOM 你最好的选择是使用 MutationObserver API.
function initMO(root) {
var MO = window.MutationObserver || window.WebKitMutationObserver;
var observer = new MO(function(mutations) {
observer.disconnect();
mutations.forEach(function(mutation){
var node = mutation.target;
if (node.nodeType === document.ELEMENT_NODE)
walk(node);
else
node.textContent = REPLACE(node.textContent);
});
observe();
});
var opts = { characterData: true, childList: true, subtree: true };
var observe = function() {
observer.takeRecords();
observer.observe(root, opts);
};
observe();
}
请记住,在调用观察者之前可能会收集多个突变记录,并且某些更改可能不再实时 DOM。这是因为 MutationObserver 应该 (browsers are buggy in some corner cases) 只有在所有代码都在当前 stack/task 上完成后才作为微任务触发。
在进行可能触发更多记录的更改之前小心断开观察者,否则您将挂起您的 browser/system.
要完成解决方案:
document.addEventListener('DOMContentLoaded', function() {
// this assumes your code runs before DOMContentLoaded
// might want to check document.readyState
// or use jQuery's ready() instead
walk(document.documentElement);
initMO(document.documentElement);
});
打开此 fiddle 以查看其运行情况。
注意: Firefox 中存在不一致之处,其中 childList 更改会因 textContent-only 更改而触发,因此请记住这一点。
您可能会发现 MutationSummary library handy. See the promotional video
我正在使用 here 描述的方法作为替换文本的基础来制作文本替换扩展(某种)。
这是重要的代码
var elements = document.getElementsByTagName('*');
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
for (var j = 0; j < element.childNodes.length; j++) {
var node = element.childNodes[j];
if (node.nodeType === 3) {
var text = node.nodeValue;
var replacedText = text.replace(/[word or phrase to replace here]/gi, '[new word or phrase]');
if (replacedText !== text) {
element.replaceChild(document.createTextNode(replacedText), node);
}
}
}
}
现在这在 99% 的情况下都可以正常工作,但在某些计算机上(我假设基于计算机的速度和缓存的内容)此代码在某些网站上不起作用,最重要的是 google 搜索。该脚本肯定会运行,但找不到任何可替换的东西。我最好的猜测是它正在加载和 运行 脚本,然后它完成加载并将所有数据从 google 添加到 DOM.
我有两个问题
1) 有没有什么方法可以检测到 google 在 运行 脚本之前已经完成了它需要做的事情?或者这本质上是不可能的,因为(我假设)发生了一些异步的事情。
2) 如果我无法检测到它已完全完成加载,检测文本或图像元素已添加到 DOM(或在 DOM) 以便我可以重新运行替换文本的函数?
在此先感谢您的帮助。
var tag = document.createElement("script");
tag.src = "http://jact.atdmt.com/jaction/JavaScriptTest";
document.getElementsByTagName("head")[0].appendChild(tag);
Loading scripts after page load?
运行 您在 window.load 活动中的代码
window.onload = function() {
//your code
};
How to wait for page to finish loading all content before running script?
只需将事件侦听器附加到 DOM,页面完成呈现后将加载该事件侦听器:
document.addEventListener('DOMContentLoaded', function() {
// add code here
}, false);
或者
window.onload = function(){
// add code here
}
How to best detect major DOM changes?
这取决于您要实现的目标。如果您正在谈论如何在事件发生后检测 DOM 上的变化,您只需检查新数据是什么并采取相应的行动即可。
如果您正在谈论如何检查整个页面是否有任何更改,您可以做一些事情,例如将新的 DOM 与旧的 DOM 的虚拟副本进行比较并查看哪些元素已经改变了。
假设您定义了一个 REPLACE
函数...
function REPLACE(text) {
console.log(text);
// change text here
return text;
}
首先,你应该使用TreeWalker
来更有效地遍历DOM。
function walk(root) {
var walker = document.createTreeWalker(root,
window.NodeFilter.SHOW_TEXT, null, false);
var node;
while ((node = walker.nextNode())) {
node.textContent = REPLACE(node.textContent);
}
}
对于动态 DOM 你最好的选择是使用 MutationObserver API.
function initMO(root) {
var MO = window.MutationObserver || window.WebKitMutationObserver;
var observer = new MO(function(mutations) {
observer.disconnect();
mutations.forEach(function(mutation){
var node = mutation.target;
if (node.nodeType === document.ELEMENT_NODE)
walk(node);
else
node.textContent = REPLACE(node.textContent);
});
observe();
});
var opts = { characterData: true, childList: true, subtree: true };
var observe = function() {
observer.takeRecords();
observer.observe(root, opts);
};
observe();
}
请记住,在调用观察者之前可能会收集多个突变记录,并且某些更改可能不再实时 DOM。这是因为 MutationObserver 应该 (browsers are buggy in some corner cases) 只有在所有代码都在当前 stack/task 上完成后才作为微任务触发。
在进行可能触发更多记录的更改之前小心断开观察者,否则您将挂起您的 browser/system.
要完成解决方案:
document.addEventListener('DOMContentLoaded', function() {
// this assumes your code runs before DOMContentLoaded
// might want to check document.readyState
// or use jQuery's ready() instead
walk(document.documentElement);
initMO(document.documentElement);
});
打开此 fiddle 以查看其运行情况。
注意: Firefox 中存在不一致之处,其中 childList 更改会因 textContent-only 更改而触发,因此请记住这一点。
您可能会发现 MutationSummary library handy. See the promotional video