当我用 <span> 标记替换字符串时,MutationObserver 创建无限循环
MutationObserver create infinite loop when I replace a string with <span> tag
我想用 html contenteditable div 替换所有事件。我需要用标签替换发生的事件,以使用 css 对其进行自定义。
但是当我尝试用跨度替换时,MutationObserver 生成一个无限循环...
document.designMode = "on";
var text = document.getElementById('text');
let observer = new MutationObserver(mutations =>
mutations.forEach(mutation => {
console.log(text.textContent);
// let a = "a";
// a.style.color = "red";
text.textContent = text.textContent.replace('/', '<span>/</span>');
observer.disconnect();
const range = document.createRange();
const textNode = text.firstChild;
range.setStart(textNode, text.textContent.length);
range.setEnd(textNode, text.textContent.length);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
// observer.disconnect();
})
);
observer.observe(text, {
childList: true,
characterData: true,
subtree: true,
});
<p id="text" contenteditable="true">I'm a text will be change</p>
无限循环是由于用 <span>/</span>
替换键入的 /
字符而没有先关闭观察器 - 每次替换都会再次触发观察器。
这个问题的解决方法很简单:更换前关闭观察器,然后再打开:
"use strict";
document.designMode = "on";
var text = document.getElementById('text');
let observer = new MutationObserver(mutations =>
mutations.forEach(mutation => {
console.log(text.textContent);
observer.disconnect(); // turn observer off;
text.textContent = text.textContent.replace('/', '<span>/</span>');
const range = document.createRange();
const textNode = text.firstChild;
range.setStart(textNode, text.textContent.length);
range.setEnd(textNode, text.textContent.length);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
observe(); // turn back on
})
);
const observe = ()=> {
observer.observe(text, {
childList: true,
characterData: true,
subtree: true,
});
};
observe();
span { background-color: yellow;}
<p id="text" contenteditable="true">I'm a text will be change</p>
但这只是突出了一个潜在的新问题:代码将 textContent
替换为 HTML,因为它在文本节点内,所以以源代码形式显示,并且因为 <span>/</span>
在文本节点内,CSS 以黄色突出显示 SPAN 元素不起作用(它不是 SPAN 元素)。
假设 span 元素应该呈现为 HTML,现在的设计问题变成了如何用 DOM 中的 SPAN 元素替换新键入的正斜杠,而不是在文本节点中。 Mutation Records 的 mutation.target
属性 可能是一个很好的起点,将其分成三个节点:/
之前的文本节点,<span>/</span>
的元素节点和/
之后的文本的最终文本节点(如果有),如果需要,随后将光标重新定位在跨度节点之后。
我想用 html contenteditable div 替换所有事件。我需要用标签替换发生的事件,以使用 css 对其进行自定义。 但是当我尝试用跨度替换时,MutationObserver 生成一个无限循环...
document.designMode = "on";
var text = document.getElementById('text');
let observer = new MutationObserver(mutations =>
mutations.forEach(mutation => {
console.log(text.textContent);
// let a = "a";
// a.style.color = "red";
text.textContent = text.textContent.replace('/', '<span>/</span>');
observer.disconnect();
const range = document.createRange();
const textNode = text.firstChild;
range.setStart(textNode, text.textContent.length);
range.setEnd(textNode, text.textContent.length);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
// observer.disconnect();
})
);
observer.observe(text, {
childList: true,
characterData: true,
subtree: true,
});
<p id="text" contenteditable="true">I'm a text will be change</p>
无限循环是由于用 <span>/</span>
替换键入的 /
字符而没有先关闭观察器 - 每次替换都会再次触发观察器。
这个问题的解决方法很简单:更换前关闭观察器,然后再打开:
"use strict";
document.designMode = "on";
var text = document.getElementById('text');
let observer = new MutationObserver(mutations =>
mutations.forEach(mutation => {
console.log(text.textContent);
observer.disconnect(); // turn observer off;
text.textContent = text.textContent.replace('/', '<span>/</span>');
const range = document.createRange();
const textNode = text.firstChild;
range.setStart(textNode, text.textContent.length);
range.setEnd(textNode, text.textContent.length);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
observe(); // turn back on
})
);
const observe = ()=> {
observer.observe(text, {
childList: true,
characterData: true,
subtree: true,
});
};
observe();
span { background-color: yellow;}
<p id="text" contenteditable="true">I'm a text will be change</p>
但这只是突出了一个潜在的新问题:代码将 textContent
替换为 HTML,因为它在文本节点内,所以以源代码形式显示,并且因为 <span>/</span>
在文本节点内,CSS 以黄色突出显示 SPAN 元素不起作用(它不是 SPAN 元素)。
假设 span 元素应该呈现为 HTML,现在的设计问题变成了如何用 DOM 中的 SPAN 元素替换新键入的正斜杠,而不是在文本节点中。 Mutation Records 的 mutation.target
属性 可能是一个很好的起点,将其分成三个节点:/
之前的文本节点,<span>/</span>
的元素节点和/
之后的文本的最终文本节点(如果有),如果需要,随后将光标重新定位在跨度节点之后。