Javascript: Как проверить, изменился ли внутренний контент элемента? [Дубликат]

Это одно из самых запутанных сообщений об ошибках, которые каждый программист VC ++ видел снова и снова. Давайте сначала сделаем чёткость.

A. Что такое символ? Короче говоря, символ - это имя. Это может быть имя переменной, имя функции, имя класса, имя typedef или что-либо кроме тех имен и знаков, которые принадлежат языку C ++. Он определяется пользователем или вводится библиотекой зависимостей (другой пользовательский).

B. Что является внешним? В VC ++ каждый исходный файл (.cpp, .c и т. Д.) Рассматривается как единица перевода, компилятор компилирует по одному модулю за раз и генерирует один объектный файл (.obj) для текущей единицы перевода. (Обратите внимание, что каждый заголовочный файл, включенный в этот исходный файл, будет предварительно обработан и будет рассматриваться как часть этой единицы перевода). Все внутри единицы перевода считается внутренним, все остальное считается внешним. В C ++ вы можете ссылаться на внешний символ, используя ключевые слова, такие как extern, __declspec (dllimport) и т. Д.

C. Что такое «решимость»? Resolve - термин времени связывания. Во время компоновки линкер пытается найти внешнее определение для каждого символа в объектных файлах, которые не могут найти свое определение внутри. Объем этого процесса поиска, включая:

  • Все объектные файлы, сгенерированные во время компиляции
  • Все библиотеки (.lib), которые явно или неявно указаны как дополнительные зависимости это строительное приложение.

Этот процесс поиска называется разрешением.

D. Наконец, почему Unresolved External Symbol? Если компоновщик не может найти внешнее определение для символа, который не имеет определения внутри, он сообщает об ошибке неразрешенного внешнего символа.

E. Возможные причины LNK2019: ошибка неразрешенного внешнего символа. Мы уже знаем, что эта ошибка связана с тем, что компоновщик не смог найти определение внешних символов, возможные причины могут быть отсортированы как:

  1. Определение существует

Например, если у нас есть функция foo, определенная в a.cpp:

int foo()
{
    return 0;
}

В b.cpp мы хотим вызвать функцию foo, поэтому добавим

void foo();

, чтобы объявить функцию foo () и вызвать ее в другом теле функции, скажем bar():

void bar()
{
    foo();
}

Теперь, когда вы создаете этот код, вы получите ошибку LNK2019, жалуясь, что foo является неразрешенным символом , В этом случае мы знаем, что foo () имеет свое определение в a.cpp, но отличается от того, которое мы вызываем (другое возвращаемое значение). Это означает, что определение существует.

  1. Определение не существует

Если мы хотим вызвать некоторые функции в библиотеке, но библиотека импорта не добавлен в дополнительный список зависимостей (установленный из: Project | Properties | Configuration Properties | Linker | Input | Additional Dependency) вашего проекта. Теперь компоновщик сообщит LNK2019, поскольку определение не существует в текущей области поиска.

174
задан Joe Frambach 6 December 2013 в 23:39
поделиться

6 ответов

2015, новый MutationObserver поддерживается современными браузерами:

Chrome 18+, Firefox 14+, IE 11+, Safari 6 +

Если вам нужно поддерживать более старые, вы можете попытаться вернуться к другим подходам, подобным тем, которые упомянуты в этом предыдущем ответе 5 (!)). Там есть драконы. Наслаждайтесь :)


Кто-то еще меняет документ? Поскольку, если у вас есть полный контроль над изменениями, вам просто нужно создать свой собственный API domChanged - с функцией или настраиваемым событием - и вызвать / вызвать его везде, где вы меняете.

Уровень DOM Level-2 имеет типы событий мутации , но более старая версия IE не поддерживает его. Обратите внимание, что события мутации устарели в спецификации DOM3 Events и имеют производительность .

Вы можете попытаться эмулировать событие мутации с помощью onpropertychange в IE (и вернуться к подходу грубой силы, если не доступно).

Для full domChange интервал может быть чрезмерным. Представьте, что вам нужно сохранить текущее состояние всего документа и изучить каждое свойство каждого элемента как одно и то же.

Возможно, если вас интересуют только элементы и их порядок (как вы упомянули в ваш вопрос), getElementsByTagName("*") может работать. Это автоматически срабатывает, если вы добавите элемент, удалите элемент, замените элементы или измените структуру документа.

Я написал доказательство концепции:

(function (window) {
    var last = +new Date();
    var delay = 100; // default delay

    // Manage event queue
    var stack = [];

    function callback() {
        var now = +new Date();
        if (now - last > delay) {
            for (var i = 0; i < stack.length; i++) {
                stack[i]();
            }
            last = now;
        }
    }

    // Public interface
    var onDomChange = function (fn, newdelay) {
        if (newdelay) delay = newdelay;
        stack.push(fn);
    };

    // Naive approach for compatibility
    function naive() {

        var last = document.getElementsByTagName('*');
        var lastlen = last.length;
        var timer = setTimeout(function check() {

            // get current state of the document
            var current = document.getElementsByTagName('*');
            var len = current.length;

            // if the length is different
            // it's fairly obvious
            if (len != lastlen) {
                // just make sure the loop finishes early
                last = [];
            }

            // go check every element in order
            for (var i = 0; i < len; i++) {
                if (current[i] !== last[i]) {
                    callback();
                    last = current;
                    lastlen = len;
                    break;
                }
            }

            // over, and over, and over again
            setTimeout(check, delay);

        }, delay);
    }

    //
    //  Check for mutation events support
    //

    var support = {};

    var el = document.documentElement;
    var remain = 3;

    // callback for the tests
    function decide() {
        if (support.DOMNodeInserted) {
            window.addEventListener("DOMContentLoaded", function () {
                if (support.DOMSubtreeModified) { // for FF 3+, Chrome
                    el.addEventListener('DOMSubtreeModified', callback, false);
                } else { // for FF 2, Safari, Opera 9.6+
                    el.addEventListener('DOMNodeInserted', callback, false);
                    el.addEventListener('DOMNodeRemoved', callback, false);
                }
            }, false);
        } else if (document.onpropertychange) { // for IE 5.5+
            document.onpropertychange = callback;
        } else { // fallback
            naive();
        }
    }

    // checks a particular event
    function test(event) {
        el.addEventListener(event, function fn() {
            support[event] = true;
            el.removeEventListener(event, fn, false);
            if (--remain === 0) decide();
        }, false);
    }

    // attach test events
    if (window.addEventListener) {
        test('DOMSubtreeModified');
        test('DOMNodeInserted');
        test('DOMNodeRemoved');
    } else {
        decide();
    }

    // do the dummy test
    var dummy = document.createElement("div");
    el.appendChild(dummy);
    el.removeChild(dummy);

    // expose
    window.onDomChange = onDomChange;
})(window);

Использование:

onDomChange(function(){ 
    alert("The Times They Are a-Changin'");
});

Это работает на IE 5.5+, FF 2+, Chrome, Safari 3+ и Opera 9.6 +

166
ответ дан 19 revs, 3 users 69% 25 August 2018 в 17:53
поделиться

Использовать JQuery MutationObserver , как показано в блоге Gabriele Romanato

Chrome 18+, Firefox 14+, IE 11+, Safari 6 +

// The node to be monitored
var target = $( "#content" )[0];

// Create an observer instance
var observer = new MutationObserver(function( mutations ) {
  mutations.forEach(function( mutation ) {
    var newNodes = mutation.addedNodes; // DOM NodeList
    if( newNodes !== null ) { // If there are new nodes added
        var $nodes = $( newNodes ); // jQuery set
        $nodes.each(function() {
            var $node = $( this );
            if( $node.hasClass( "message" ) ) {
                // do something
            }
        });
    }
  });    
});

// Configuration of the observer:
var config = { 
    attributes: true, 
    childList: true, 
    characterData: true 
};

// Pass in the target node, as well as the observer options
observer.observe(target, config);

// Later, you can stop observing
observer.disconnect();
1
ответ дан Anthony Awuley 25 August 2018 в 17:53
поделиться

или вы можете просто создать свое собственное событие, которое выполняется везде

 $("body").on("domChanged", function () {
                //dom is changed 
            });


 $(".button").click(function () {

          //do some change
          $("button").append("<span>i am the new change</span>");

          //fire event
          $("body").trigger("domChanged");

        });

Полный пример http://jsfiddle.net/hbmaam/Mq7NX/

8
ответ дан HB MAAM 25 August 2018 в 17:53
поделиться
12
ответ дан Jacob van Lingen 25 August 2018 в 17:53
поделиться

Как насчет расширения jquery для этого?

   (function () {
        var ev = new $.Event('remove'),
            orig = $.fn.remove;
        var evap = new $.Event('append'),
           origap = $.fn.append;
        $.fn.remove = function () {
            $(this).trigger(ev);
            return orig.apply(this, arguments);
        }
        $.fn.append = function () {
            $(this).trigger(evap);
            return origap.apply(this, arguments);
        }
    })();
    $(document).on('append', function (e) { /*write your logic here*/ });
    $(document).on('remove', function (e) { /*write your logic here*/ ) });

Jquery 1.9+ построил поддержку для этого (я слышал, что не тестировался).

0
ответ дан StartCoding 25 August 2018 в 17:53
поделиться

Это предельный подход до сих пор с наименьшим кодом:

IE9 +, FF, Webkit:

Использование MutationObserver и откат к устаревшим событиям мутации , если необходимо: (Пример ниже, если только для изменений DOM относительно добавленных или удаленных узлов)

var observeDOM = (function(){
  var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

  return function( obj, callback ){
    if( !obj || !obj.nodeType === 1 ) return; // validation

    if( MutationObserver ){
      // define a new observer
      var obs = new MutationObserver(function(mutations, observer){
        if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
          callback( mutations[0] );
      });
      // have the observer observe foo for changes in children
      obs.observe( obj, { childList:true, subtree:true });
    }
    
    else if( window.addEventListener ){
      obj.addEventListener('DOMNodeInserted', callback, false);
      obj.addEventListener('DOMNodeRemoved', callback, false);
    }
  }
})();

//------------< DEMO BELOW >----------------
// add item
document.querySelector('body > button').onclick = function(e){
  var newElmHTML = "<li><button>list item (click to delete)</button></li>";
  document.querySelector('ol').insertAdjacentHTML("beforeend", newElmHTML);
}

// delete item
document.querySelector('ol').onclick = function(e){
  if( e.target.nodeName == "BUTTON" )
    e.target.parentNode.parentNode.removeChild(e.target.parentNode);
}
    
// Observe a specific DOM element:
observeDOM( document.querySelector('ol'), function(m){ 
  console.clear();
  console.log('Added:', m.addedNodes, 'Removed:', m.removedNodes);
});
<button>Add Item</button>
<ol>
  <li><button>list item (click to delete)</button></li>
  <li><button>list item (click to delete)</button></li>
  <li><button>list item (click to delete)</button></li>
  <li><button>list item (click to delete)</button></li>
</ol>

185
ответ дан vsync 25 August 2018 в 17:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: