【问题标题】:MutationObserver create infinite loop when I replace a string with <span> tag当我用 <span> 标签替换字符串时,MutationObserver 创建无限循环
【发布时间】:2021-04-05 15:15:40
【问题描述】:

我想用 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>

【问题讨论】:

    标签: javascript dom dom-events contenteditable mutation-observers


    【解决方案1】:

    无限循环是由 &lt;span&gt;/&lt;/span&gt; 替换键入的 / 字符引起的,而没有先关闭观察者 - 每次替换都会再次触发观察者。

    这个问题的解决方法很简单:更换前关闭观察器,之后再打开:

    "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;}
    &lt;p id="text" contenteditable="true"&gt;I'm a text will be change&lt;/p&gt;

    但这只会突出一个潜在的新问题:代码用 HTML 替换 textContent,因为它在文本节点内,以源形式显示,并且因为 &lt;span&gt;/&lt;/span&gt; 在文本节点内,CSS 突出显示 SPAN黄色的元素不起作用(它不是 SPAN 元素)。

    假设 span 元素应该呈现为 HTML,那么设计问题现在变成了如何用 DOM 中的 SPAN 元素而不是文本节点中的新键入的正斜杠替换。 Mutation Records 的 mutation.target 属性可能是一个很好的起点,可以将其拆分为三个节点:/ 之前的文本文本节点、&lt;span&gt;/&lt;/span&gt; 的元素节点和/ 之后的文本的最终文本节点如果有,然后根据需要将光标重新定位到 span 节点之后。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-21
      • 2016-08-27
      相关资源
      最近更新 更多