Получить новое значение атрибута для текущего MutationRecord при использовании MutationObserver? - PullRequest
1 голос
/ 09 марта 2020

У меня есть некоторый код, подобный следующему,

const observer = new MutationObserver(records => {
    for (const record of records) {
        if (record.type !== 'attributes') continue

        handleAttrChange(
            record.attributeName!,
            record.oldValue,
            record.target.attributes.getNamedItem(record.attributeName).value,
        )
    }
})

, где handleAttrChange параметры - это имя атрибута, старое значение и новое значение.

Однако, как вы можете скажем, третий аргумент, переданный в handleAttrChange,

record.target.attributes.getNamedItem(record.attributeName!)!.value

, всегда будет самым последним значением атрибута, , а не "новым значением" для конкретная запись мутации, с которой мы итерируем (то есть не «новое значение», которое наблюдалось в то время, когда произошла мутация).

Как мы можем получить «новое значение» для каждой мутации как « наблюдалось ли в момент каждой мутации?

Ответы [ 2 ]

2 голосов
/ 09 марта 2020

Мы можем эмулировать это следующим образом:

const observer = new MutationObserver(records => {
    let lastAttributeValues = {}
    let name = ''

    for (const record of records) {
        if (record.type !== 'attributes') continue

        name = record.attributeName

        if (lastAttributeValues[name] === undefined) {
            lastAttributeValues[name] = record.oldValue
            continue
        }

        handleAttributeChange(name, lastAttributeValues[name], record.oldValue)

        lastAttributeValues[name] = record.oldValue
    }

    let attr

    for (const name in lastAttributeValues) {
        attr = el.attributes.getNamedItem(name)
        handleAttributeChange(name, lastAttributeValues[name], attr === null ? null : attr.value)
    }
})

Что он делает, потому что мы знаем, что мы получаем мутации по порядку, и у нас есть все значения атрибутов для данного атрибута в процессе итерации, он просто отслеживает предыдущие и текущие значения атрибута (для каждого имени атрибута) и запускает handleAttributeChange с каждым предыдущим и текущим значением.

0 голосов
/ 09 марта 2020

Я не думаю, что это возможно с MutationObserver. Ничто в MutationRecord не предоставляет нового значения, и поскольку MuationObserver выполняется в микрозадаче, а не полностью синхронно после изменения, значение, которое можно извлечь из элемента внутри наблюдателя обратный вызов, возможно, был изменен после изменения, которое вызвало наблюдателя, как вы видите.

const observer = new MutationObserver(records => {
  for (const record of records) {
    if (record.type !== 'attributes') continue
    console.log(div.dataset.foo);
    console.log(record);
  }
});
observer.observe(div, { attributes: true });

div.setAttribute('data-foo', 'foo');
div.setAttribute('data-foo', 'bar');
<div id="div"></div>

Хотя это возможно при использовании синхронного наблюдателя (прослушайте событие DOMAttrModified на элементе), они устарел и медленен.

Если вы знаете, как атрибут будет изменен, вы могли бы пропатчить этот метод, чтобы он сначала прошел через вашу собственную logi c. Например, с setAttribute:

div.setAttribute = (...args) => {
  console.log(`Setting ${args[0]} from ${div.getAttribute(args[0])} to ${args[1]}`);
  return HTMLElement.prototype.setAttribute.apply(div, args);
};

div.setAttribute('data-foo', 'foo');
div.setAttribute('data-foo', 'bar');
<div id="div"></div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...