MutationObserver记录错误的DOM元素(可编辑的div)

时间:2016-10-07 19:29:48

标签: javascript jquery html dom

请考虑以下事项:

我有contenteditable div:

<div id="contentEditableDiv" contenteditable="true">
    <p id="content0e">Lorem ipsum...</p>
    <p id="content1e">Lorem ipsum...</p>
</div>

我添加一个MutationObserver来观察JavaScript中此div中的DOM更改:

var mutationObserver = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        manipulateAddedContent(mutation);
    });
});

mutationObserver.observe(jQuery("#contentEditableDiv")[0], 
    { attributes: true, childList: true, characterData: true });

解决此问题后,我想manipulateAddedContent。然而,函数声明如下:

function manipulateAddedContent(mutation){
    jqMutation = jQuery(mutation);
    if(jqMutation.prop("addedNodes").length > 0){
        for (i = 0; i < jqMutation.prop("addedNodes").length; i++) {
            console.log(mutation.addedNodes[i]);
        }
    }
}

contenteditable div中,可以通过在现有p元素中按Enter键来添加新的p DOM元素,因此HTML看起来像:

Inspector:
    <div id="contentEditableDiv" contenteditable="true" style="...">
        <p id="content0e">Lorem ipsum...</p>
        <p id="content1e">Lorem ipsum...</p>
        <p></p>
    </div>

但MutationObserver使用p记录已存在的id="content1e"元素。

嗯,由于期望MutationObserver不能正确行事,如果你能给我一个替代解决方案,我也很高兴。

下面是一个Stack Snippet。如果单击其中一个现有p元素内的光标并按Enter键,则会创建一个新的p元素。 MutationObserver记录已存在的p元素,但不记录新创建的元素。

Stack Snippet:

var mutationObserver = new MutationObserver(function(mutations) {
	mutations.forEach(function(mutation) {
		manipulateAddedContent(mutation);
	});
});

mutationObserver.observe(jQuery("#contentEditableDiv")[0], 
  { attributes: true, childList: true, characterData: true });

function manipulateAddedContent(mutation){
	jqMutation = jQuery(mutation);
	if(jqMutation.prop("addedNodes").length > 0){
		for (i = 0; i < jqMutation.prop("addedNodes").length; i++) {
		    console.log(mutation.addedNodes[i]);
		}
	}
}
	#contentEditableDiv {
		border: 1px solid black;
		min-height: 200px;
		width: 200px;
	}

	#contentEditableDiv p{
		border: 1px solid red;
		margin-left: 5px;
		margin-right: 5px;
	}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

<div id="contentEditableDiv" contenteditable="true" >
  <p id="content0">Lorem ipsum...</p>
  <p id="content1">Lorem ipsum...</p>
</div>

那么为什么MutationObserver会记录错误的元素?

我该如何解决? =&GT;如何获取新添加的p元素(没有id)?

2 个答案:

答案 0 :(得分:0)

一种解决方案非常简单。我只是让我得到返回的一个DOM元素:

var mutationObserver = new MutationObserver(function(mutations) {
	mutations.forEach(function(mutation) {
		manipulateAddedContent(mutation);
	});
});

mutationObserver.observe(jQuery("#contentEditableDiv")[0], 
  { attributes: true, childList: true, characterData: true });

function manipulateAddedContent(mutation){
	jqMutation = jQuery(mutation);
	if(jqMutation.prop("addedNodes").length > 0){
		for (i = 0; i < jqMutation.prop("addedNodes").length; i++) {
		    if(typeof jQuery(mutation.addedNodes[i]).next()[0] !== "undefined"){
			    console.log(jQuery(mutation.addedNodes[i]).next()[0]);
		    }
		}
	}
}
	#contentEditableDiv {
		border: 1px solid black;
		min-height: 200px;
		width: 200px;
	}

	#contentEditableDiv p{
		border: 1px solid red;
		margin-left: 5px;
		margin-right: 5px;
	}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

<div id="contentEditableDiv" contenteditable="true" >
  <p id="content0">Lorem ipsum...</p>
  <p id="content1">Lorem ipsum...</p>
</div>

但我不接受我的回答,因为我仍然不知道为什么mutationObserver会返回错误的元素。

答案 1 :(得分:0)

这与 MutationObserver 无关,它没有返回错误的元素。当您在 contenteditable 容器内的任何元素内按 Enter 时,它会被复制,这就是 MutationObserver 报告的元素具有相同 ID 的原因。如果您尝试通过 DevTools 定位该元素,它会向您显示最近添加的元素 - 因为它具有相同的 id。

#uniqueOrIsIt {
 border: 1px solid gold;
}
.paragraph {
 border: 1px solid blue;
}
<div contenteditable="true">
  <p id="uniqueOrIsIt">text</p>
  <p class="paragraph">text</p>
  <p style="border: 1px solid green;color:green">text</p>
</div>

所有三个 p 元素都将使用完全相同的属性进行复制。

解决方案取决于您要完成的任务 - 您是否希望每个插入的 p 元素都有一个新的唯一 ID?在这种情况下,您可以为每个突变检查 addedNodes 中的任何一个是否为 p 元素,如果是,则为它们分配一个唯一的 id。保持简单的 let counter = 1 并将 ID 设置为 addedNode.setAttribute('id', ('content' + counter++))