MutationObserver is easy to use.
    First, we create an observer with a callback-function:

    1. let observer = new MutationObserver(callback);

    And then attach it to a DOM node:

    1. observer.observe(node, config);

    config is an object with boolean options “what kind of changes to react on”:

    • childList – changes in the direct children of node,
    • subtree – in all descendants of node,
    • attributes – attributes of node,
    • attributeFilter – an array of attribute names, to observe only selected ones.
    • characterData – whether to observe node.data (text content),

    Few other options:

    • attributeOldValue – if true, pass both the old and the new value of attribute to callback (see below), otherwise only the new one (needs attributes option),
    • characterDataOldValue – if true, pass both the old and the new value of node.data to callback (see below), otherwise only the new one (needs characterData option).

    Then after any changes, the callback is executed: changes are passed in the first argument as a list of MutationRecord objects, and the observer itself as the second argument.
    MutationRecord objects have properties:

    • type– mutation type, one of
      • "attributes": attribute modified
      • "characterData": data modified, used for text nodes,
      • "childList": child elements added/removed,
    • target – where the change occurred: an element for "attributes", or text node for "characterData", or an element for a "childList" mutation,

    这里的target是发生变动的节点,而非被观察的节点

    • addedNodes/removedNodes – nodes that were added/removed,
    • previousSibling/nextSibling – the previous and next sibling to added/removed nodes,
    • attributeName/attributeNamespace – the name/namespace (for XML) of the changed attribute,
    • oldValue – the previous value, only for attribute or text changes, if the corresponding option is set attributeOldValue/characterDataOldValue.