Introduction: There have been many articles on MutationObserver, but very few articles on MutationObserverInit, which is not very friendly to someone who doesn’t know about it

What is a MutationObserverInit

First, let’s look at MDN’s description of MutationObserverInit:

The MutationObserverInit dictionary describes the configuration of the MutationObserver. Therefore, it is primarily used as an argument type for the mutationObserver.observe () method

Let’s look at some code:

// Select the nodes that need to be observed to change
const target = document.querySelector('#demo')

// Observer configuration (what changes need to be observed)
const config = { attributes: true.childList: true.subtree: true }

// The callback function that is executed when changes are observed
function callback(mutationList, observer) {
  for(let mutationRecord of mutationList) {
    console.log(mutationRecord.type); }}// Create an observer instance and pass in the callback function
const observer = new MutationObserver(callback)

// The callback method of the MutationObserver object is configured to start receiving notifications of DOM changes matching the given option
observer.observe(target, config)
Copy the code

This code is a use case for MutationObserver. In this code we define the config variable, which sets the configuration items (what changes need to be observed) for the observer to observe the node. In plain English MutationObserverInit is the option for this configuration item.

The body of the

For a better understanding, I divide these configuration items into primary and secondary configuration items. The master configuration item contains childList, Attributes, and characterData attributes. When observing (), at least one of these attributes must be true; otherwise, TypeError will be raised.

Let’s begin to explain them in a formal way, with the secondary configuration items paired with the main configuration items.

1, childList that consists

ChildList has only one auxiliary configuration item, subtree, but beginners can easily confuse childList and Subtree because they both involve nodes. ChildList is responsible for monitoring child nodes, while Subtree is responsible for monitoring child nodes to bubble up to the monitored node, triggering the callback function. Yes, here we can use event listening to understand subtree:

When we do not set subtree or subtree: false, we can use the following code to understand:

target.addEventListener('click'.function(e) {
    if(this === e.target) {
        console.log(e)
    }
})
Copy the code

When we set subtree: true, we can understand this with the following code:

target.addEventListener('click'.function(e) {
    console.log(e)
})
Copy the code

MDN describes childList and subtree as follows:

ChildList basic usage

<div id="demo">
  <div data-id="12">
    <p>The paragraph</p>
  </div>
  <div data-id="13">
  	<p>The paragraph</p>
  </div>
</div>
Copy the code
const target = document.querySelector('#demo')
const observer = new MutationObserver(callback)

observer.observe(target, {
	childList: true
})

// The following operation triggers the callback function (adding or deleting monitored nodes)
target.firstElementChild.remove()
target.insertAdjacentHTML('afterbegin'.'<div>insertAdjacentHTML afterbegin</div>')

// The following operations do not trigger the callback function (adding or deleting descendant nodes of the monitored node)
target.firstElementChild.firstElementChild.remove()
target.firstElementChild.insertAdjacentHTML('afterbegin'.'<div>insertAdjacentHTML afterbegin</div>')
Copy the code

childList + subtree

observer.observe(target, {
	childList: true.subtree: true
})

// All of the following operations trigger callbacks (adding and deleting children and descendants of the monitored node)
target.firstElementChild.remove()
target.insertAdjacentHTML('afterbegin'.'<div>insertAdjacentHTML afterbegin</div>')
target.firstElementChild.firstElementChild.remove()
target.firstElementChild.firstElementChild.insertAdjacentHTML('afterbegin'.'<span>insertAdjacentHTML afterbegin</span>')
Copy the code

2, the attributes

Attributes is used to monitor attribute changes of target elements. Its auxiliary configuration items include attributeOldValue, attributeFilter, and Subtree. MDN introduces them as follows:

Attributes basic usage

Attributes only monitors changes in the value of the target node attribute (any attribute).

<div id="demo">
  <div data-id="12">child-12</div>
  <div data-id="13">child-13</div>
</div>
Copy the code
const target = document.querySelector('#demo')
const observer = new MutationObserver(callback)

observer.observe(target, { 
	attributes: true
})

// The current operation triggers the callback function
target.title = 'attribute'

// The current operation does not trigger a return function
target.firstElementChild.title = 'child-12'
Copy the code

attributes + attributeOldValue

observer.observe(target, {
	attributes: true.attributeOldValue: true
})
Copy the code

The current configuration not only monitors changes in the value of the target node property (any property), but also records the value before the change in the MutationRecord.

Callback <mutationList, Observer > is an array of mutationRecords

attributes + attributeFilter

An attributeFilter is an array. If you set an attributeFilter to an array, only the attributes in the array change. If the attribute name does not exist in the array, the callback function is not triggered

observer.observe(target, {
	attributes: true.attributeFilter: ['title'.'class'.'style']})// The current operation triggers the callback function
target.title = 'attribute'

// The current operation does not trigger the callback function
target.dataset.id = 15
Copy the code

attributes + subtree

When subtree is set to true, you can observe the changes in the attribute values of both the target node and its descendants.

observer.observe(target, {
	attributes: true.subtree: true
})

// The current operation triggers the callback function
target.title = 'attribute'

// The current operation triggers a return to the function
target.firstElementChild.title = 'child-12'
Copy the code

3, characterData

CharacterData is used to monitor changes in the value of a text node. Its auxiliary configuration items are characterDataOldValue and Subtree, which I think are easy to see after the previous description.

It’s worth noting, however, that characterData is slightly different from Attributes and childList in that characterData only monitors the text node itself and does not monitor the contents of HTMLElement, even though it contains only text. Therefore, MutationObserver cannot monitor changes in form input box text. If you need to monitor text changes, either pass the text node directly to the observe() method or set subtree: True (the monitor target is HTMLElement).

MDN describes them as follows:

characterData + characterDataOldValue

let target = document.createTextNode('characterData demo')
const observer = new MutationObserver(callback)

// Pass the text node directly to observe
observer.observe(target, {
	characterData: true.characterDataOldValue: true
})

// The current operation triggers the callback function
target.textContent = 'reassign'
Copy the code

characterData + subtree

In code, only the text node under the listening target triggers the callback function, and direct manipulation of the content rather than the text node does not trigger the callback function
<div id="demo">content</div>
Copy the code
let target = document.querySelector('#demo')
const observer = new MutationObserver(callback)

observer.observe(target, {
	characterData: true.characterDataOldValue: true.subtree: true
})

// The following operations do not trigger the callback function (operating directly on the text content of the monitor target instead of the text node under the monitor target does not trigger the callback function)
target.innerText = 'reassign'
target.textContent = 'Secondary assignment'
target.insertAdjacentText('beforeend'.'Append content')...// Operating on the text node of the monitored target node triggers the callback function. (There is only one text node under the target node.
target.firstChild.textContent = 'Valid assignment'
Copy the code
Turn on the editable properties of the label to trigger the callback function when it is entered or deleted
<div id="demo" contenteditable="true"></div>
Copy the code
observer.observe(target, {
	characterData: true.characterDataOldValue: true.subtree: true
})
Copy the code