我需要使用class="kendoTooltip"
定位所有元素,并对具有该类的任何元素运行jQuery函数。
一个html的例子是
<div class="document_wrapper">
<div>
<div class="kendoTooltip">Tooltip!</div>
</div>
</div>
我一直在尝试使用变异观察器,但无法定位页面中较深的元素。
使用以下代码,我得到了最接近的代码,但问题似乎是变异观察者仅监视音符本身及其直接子元素。我也尝试过递归调用它,但没有成功。
var mutationObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (!mutation.target.classList.contains('isRendered') && mutation.target.classList.contains('kendoTooltip')) {
renderTooltip(mutation.target);
mutation.target.classList.add('isRendered');
}
});
});
mutationObserver.observe(document.documentElement || document.body, {
childList: true,
subtree: true
});
答案 0 :(得分:0)
注意mutation.target
将是三个值之一
https://developer.mozilla.org/en-US/docs/Web/API/MutationRecord#Properties
对于属性,它是属性已更改的元素。
对于characterData,它是CharacterData节点。
对于childList,这是其子项已更改的节点。
因此,在您的情况下,target
将是body
,或者如果您的html实际上被添加到其他元素,则它将是该其他元素。因此,您当前检查target
的classList的代码将无法正常工作,因为它不是您添加的元素,而是您将其添加到的元素。
如果要检查已添加的元素,请在addedNodes列表中的每个元素上使用addingNodes属性和搜索方法,例如querySelectorAll,getElementsByClassName等,以查找目标元素。
var addedNodes = Array.from(mutation.addedNodes);
addedNodes.forEach(function(node) {
//skip textnodes
if (node.nodeType == 3) return;
//findall kendoTooltips that are not
//isRendered
var tooltips = node.querySelectorAll('.kendoTooltip:not(.isRendered)')
.forEach(renderTooltip);
});
function renderTooltip(target) {
console.log("tooltiping: ", target.textContent);
target.classList.add("isRendered");
}
var mutationObserver = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
var addedNodes = Array.from(mutation.addedNodes);
addedNodes.forEach(function(node) {
//skip textnodes
if (node.nodeType == 3) return;
//findall kendoTooltips that are not
//isRendered
var tooltips = node.querySelectorAll('.kendoTooltip:not(.isRendered)')
.forEach(renderTooltip);
});
});
});
mutationObserver.observe(document.documentElement || document.body, {
childList: true,
subtree: true
});
setTimeout(() => {
document.body.insertAdjacentHTML('beforeend', `
<div class="document_wrapper">
<div>
<div class="kendoTooltip">Tooltip!</div>
</div>
</div>`);
}, 1000);
setTimeout(() => {
document.body.insertAdjacentHTML('beforeend', `
<div class="anotherclass">
<div>
<div class="kendoTooltip">More Tooltip!</div>
</div>
</div>`);
}, 3000);
答案 1 :(得分:0)
这是一篇过时的文章,但我想我想补充一下我的想法,在尝试检测body
元素内部元素的更改时,我也遇到了类似的问题。
我并不是说我的解决方案无论如何都是好的,但是看到这个问题没有被接受的答案,也许我的想法可以帮助找到解决方案。
我的问题是我想创建一个JavaScript解决方案来检测ReactJS应用程序所使用的<div id="root"></div>
元素内部的插入,为什么要这样做的原因并不重要。
我发现将MutationObserver
附加到document
,document.documentElement
或document.body
上并没有提供任何解决方案。我最终不得不将我的MutationObserver
放入循环中,并将其附加到body
中的每个子元素上,以便可以检测到更改。
这是我的代码,我敢肯定有更好的方法可以做到这一点,但我还没有找到它:
// Public function
export function listenForDynamicComponents() {
// Create the observer
const observer = new MutationObserver((mutations) => {
// Loop each mutation
for (let i = 0; i < mutations.length; i++) {
const mutation = mutations[i];
// Check the mutation has added nodes
if (mutation.addedNodes.length > 0) {
const newNodes = mutation.addedNodes;
// Loop though each of the added nodes
for (let j = 0; j < newNodes.length; j++) {
const node = newNodes[j];
// Check if current node is a component
if (node.nodeType === 1 && node.hasAttribute('data-module')) {
// Do something here
}
// Loop though the children of each of the added nodes
for (let k = 0; k < node.childNodes.length; k++) {
const childNode = node.childNodes[k];
// Check if current child node is a compoennt
if (childNode.nodeType === 1 && childNode.hasAttribute('data-module')) {
// Do something here
}
}
}
}
}
});
// Get all nodes within body
const bodyNodes = document.body.childNodes;
// Loop though all child nodes of body
for (let i = 0; i < bodyNodes.length; i++) {
const node = bodyNodes[i];
// Observe on each child node of body
observer.observe(node, {
attributes: false,
characterData: false,
childList: true,
subtree: true,
attributeOldValue: false,
characterDataOldValue: false
});
}
}
我希望这会有所帮助。
答案 2 :(得分:0)
为了记录,与某些评论中所说的相反,subtree
选项将针对所有后代:被观察元素的孩子,孩子的孩子......但仅限于那些直接从 DOM 添加或删除。请参阅 here 和 here。顺便说一下,有一个陷阱。想象一下,您想观察一个 video
标签,它没有直接附加到 DOM,而是附加到一个分离的 DOM,比如 div.video-container
,并且它是添加到 DOM 的容器。>
const mutationInstance = new MutationObserver((mutations) => {
// The <video> is not directly added to the DOM, so wee need to query it on each added nodes
const videoContainer = mutations
.reduce((addedNodes, mutationRecord) => {
return [
...addedNodes,
...(Array.from(mutationRecord.addedNodes)),
];
}, [])
.find((element) => {
return element.querySelector("video") !== null;
});
const videoElement = videoContainer.querySelector("video");
console.log('Video element is', videoElement);
});
mutationInstance.observe(document, {
subtree: true,
childList: true,
});
触发突变的代码
const div = document.createElement('div');
div.classList.add('video-container');
const video = document.createElement('video');
// This **does not trigger** a mutation on the document
div.appendChild(video);
// This **triggers** a mutation on the document
document.body.appendChild(div);
答案 3 :(得分:-1)
我很确定您不能像事件那样委派MutationObserver
(尽管,公平地说,我从未实际尝试过)。我认为您需要为每个元素创建一个新的。
document.querySelectorAll(".kendoTooltip").forEach(function (tooltip) {
var mutationObserver = new MutationObserver(function (mutations) {
// ...
});
mutationObserver.observe(tooltip, {
// ...
});
});
就其价值而言,在添加renderTooltip
类时触发isRendered
函数要容易得多,而不必担心MutationObserver