javascript - event - اكتشاف التغييرات في DOM



javascript animation (4)

هذا هو النهج النهائي حتى الآن ، مع أصغر رمز:

IE9 + ، FF ، Webkit:

استخدام MutationObserver والعودة إلى أحداث الطفرات التي تم إيقافها عند الحاجة:
(مثال أدناه فيما يتعلق فقط بتغيرات DOM المتعلقة بالعقد الملحقة أو التي تمت إزالتها)

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

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

// Observe a specific DOM element:
observeDOM( document.getElementById('dom_element') ,function(){ 
    console.log('dom changed');
});

https://src-bin.com

أرغب في تنفيذ وظيفة عند إضافة بعض div أو input إلى html. هل هذا ممكن؟

على سبيل المثال ، يتم إضافة إدخال نص ، ثم يجب استدعاء الدالة.


Answer #1

تحديث 2015 ، يدعم MutationObserver الجديد بواسطة المتصفحات الحديثة:

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

إذا كنت بحاجة إلى دعم كبار السن ، فقد تحاول الرجوع إلى أساليب أخرى مثل تلك المذكورة في هذه الإجابة ( 5 ) سنة السابقة. هناك تنانين. استمتع :)

شخص آخر يقوم بتغيير المستند؟ لأنه إذا كانت لديك السيطرة الكاملة على التغييرات ، فأنت تحتاج فقط إلى إنشاء واجهة برمجة تطبيقات domChanged الخاصة بك - مع وظيفة أو حدث مخصص - وتشغيلها / الاتصال بها في كل مكان تقوم بتعديل الأشياء فيه.

يحتوي DOM Level-2 على أنواع أحداث التغير ، لكن الإصدار الأقدم من IE لا يدعمها. لاحظ أن أحداث الطفرة تم إيقافها في مواصفات أحداث DOM3 ولها عقوبة الأداء .

يمكنك محاولة محاكاة حدث الطفرة مع onpropertychange في IE (والعودة إلى نهج القوة الغاشمة إذا كان غير متوفر).

للحصول على 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+


Answer #2

لقد كتبت مؤخرًا jquery.initialize يقوم بذلك بالضبط - jquery.initialize

يمكنك استخدامه بنفس طريقة وظيفة

$(".some-element").initialize( function(){
    $(this).css("color", "blue"); 
});

الفرق من .each هو - يأخذ المختار الخاص بك ، في هذه الحالة. .some-element وانتظر عناصر جديدة مع هذا المحدد في المستقبل ، إذا تمت إضافة هذا العنصر ، سيتم التهيئة أيضا.

في حالتنا تهيئة وظيفة فقط تغيير لون العنصر إلى اللون الأزرق. لذا ، إذا أضفنا عنصرًا جديدًا (بغض النظر عما إذا كان مع ajax أو حتى F12 مفتش أو أي شيء) مثل:

$("<div/>").addClass('some-element').appendTo("body"); //new element will have blue color!

سيبدأ البرنامج المساعد على الفور. كما يعمل المكون الإضافي أيضًا على تهيئة عنصر واحد فقط مرة واحدة. لذلك إذا قمت بإضافة عنصر ، ثم .detach() فإنه من الجسم ثم إضافته مرة أخرى ، لن تتم تهيئته مرة أخرى.

$("<div/>").addClass('some-element').appendTo("body").detach()
    .appendTo(".some-container");
//initialized only once

ويستند البرنامج المساعد على MutationObserver - فإنه يعمل على IE9 و 10 مع التبعيات كما هو مفصل في jquery.initialize .


Answer #3

ماذا عن توسيع مسج هذا؟

   (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+ ببناء الدعم لهذا (لقد سمعت لم تختبر).





mutation-observers