ডিওমে পরিবর্তনগুলি সনাক্ত করুন


242

এইচটিএমএলে কিছু ডিভ বা ইনপুট যুক্ত হলে আমি একটি ফাংশন সম্পাদন করতে চাই। এটা কি সম্ভব?

উদাহরণস্বরূপ, একটি পাঠ্য ইনপুট যুক্ত করা হয়, তারপরে ফাংশনটি কল করা উচিত।


1
যদি কোনও তৃতীয় পক্ষের স্ক্রিপ্ট ডোমগুলিতে নোড যোগ না করে, এটি প্রয়োজনীয় নয়।
জাস্টিন জনসন



4
@ জাস্টিন জনসন যদি আপনি ক্রোম এক্সটেনশন তৈরি করেন যা জেএস কোডকে ইনজেকশন দেয় তবে এটি কার্যকর।
ফ্লুরোসেন্টগ্রিন 5

উত্তর:


206

2015 আপডেট, নতুন MutationObserverআধুনিক ব্রাউজারগুলি দ্বারা সমর্থিত:

ক্রোম 18+, ফায়ারফক্স 14+, আইই 11+, সাফারি 6+

যদি আপনার বয়স্ক ব্যক্তিদের সমর্থন করার প্রয়োজন হয় তবে আপনি নীচে এই 5 (!) বছরের পুরানো উত্তরে উল্লিখিত মতগুলির মতো অন্যান্য পন্থায় ফিরে যাওয়ার চেষ্টা করতে পারেন । ড্রাগন আছে। উপভোগ করুন :)


আর কেউ ডকুমেন্ট বদলাচ্ছেন? কারণ কোনও পরিবর্তনের উপর যদি আপনার সম্পূর্ণ নিয়ন্ত্রণ থাকে তবে আপনাকে কেবল নিজের নিজস্ব domChangedAPI তৈরি করতে হবে - কোনও ফাংশন বা কাস্টম ইভেন্ট সহ - এবং আপনি জিনিসগুলিকে সংশোধন করে সর্বত্রই এটি ট্রিগার / কল করতে হবে।

করে DOM শ্রেনী-2 আছে পরিব্যক্তি ঘটনা ধরনের , কিন্তু অর্থাত্ পুরোনো সংস্করণ তা সমর্থন করে না। নোট যে পরিব্যক্তি ঘটনা DOM3 ঘটনাবলী বৈশিষ্ট উঠিয়ে এবং আছে কর্মক্ষমতা শাস্তি

আপনি onpropertychangeIE এর সাথে মিউটেশন ইভেন্টটি অনুকরণ করার চেষ্টা করতে পারেন (এবং যদি সেগুলি না পাওয়া যায় তবে ব্রুট-ফোর্স পদ্ধতির কাছে ফিরে যেতে পারেন)।

একটি জন্য পূর্ণ 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+, এফএফ 2+, ক্রোম, সাফারি 3+ এবং অপেরা 9.6+ এ কাজ করে


4
ভাবছেন: jQuery লাইভ () কীভাবে এই সমস্যাটি সমাধান করে যদি তারা একটি ডম পরিবর্তন সনাক্ত করতে না পারে?
কিস সি বাকার

163
আমি বিশ্বাস করতে পারি না যে 2010 সালে এটি পরীক্ষা করার জন্য আপনার কাছে আই 5.5 ছিল।
অস্কার গডসন

1
@ জোস্টস্টোডোলা সাহসী আমাকেও বিরক্ত করছিলেন। আমি এটা ঠিক করার সিদ্ধান্ত নিয়েছে।
বোজাঙ্গলেস

1
মিউটেশন ইভেন্টগুলি হ্রাস করা হয়। আপনার মিউটেশনঅবার্সার ব্যবহার করা উচিত। আমি এই জাতীয় সমস্যার জন্য আমার প্লাগইন লিখেছি - github.com/AdamPietrasiak/jquery.initialize
পাই

1
কোনও মিউটেশন পর্যবেক্ষকের আগে কীভাবে আমি jquery অনক্লিক ফায়ার করতে পারি, যখন অম্বরের ক্রিয়াতে বোতামটি ক্লিক করা হয় তখন তা আগুনে ছড়িয়ে যায়? stackoverflow.com/questions/29216434/...
SuperUberDuper

219

এটি এখন পর্যন্ত চূড়ান্ত পদ্ধতির, সবচেয়ে ছোট কোড সহ:

আইই 9 +, এফএফ, ওয়েবকিট:

মিউটেশনঅবসভার ব্যবহার করে এবং প্রয়োজনে অবনমিত মিউটেশন ইভেন্টগুলিতে ফিরে আসুন :
(কেবলমাত্র নোড সংযুক্ত বা অপসারণ সংক্রান্ত ডোম পরিবর্তনের জন্য নীচের উদাহরণ)

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){
          callback(mutations);
      })
      // 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
var itemHTML = "<li><button>list item (click to delete)</button></li>",
    listElm = document.querySelector('ol');

document.querySelector('body > button').onclick = function(e){
  listElm.insertAdjacentHTML("beforeend", itemHTML);
}

// delete item
listElm.onclick = function(e){
  if( e.target.nodeName == "BUTTON" )
    e.target.parentNode.parentNode.removeChild(e.target.parentNode);
}
    
// Observe a specific DOM element:
observeDOM( listElm, function(m){ 
   var addedNodes = [], removedNodes = [];

   m.forEach(record => record.addedNodes.length & addedNodes.push(...record.addedNodes))
   
   m.forEach(record => record.removedNodes.length & removedNodes.push(...record.removedNodes))

  console.clear();
  console.log('Added:', addedNodes, 'Removed:', removedNodes);
});


// Insert 3 DOM nodes at once after 3 seconds
setTimeout(function(){
   listElm.removeChild(listElm.lastElementChild);
   listElm.insertAdjacentHTML("beforeend", Array(4).join(itemHTML));
}, 3000);
<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>
  <li><em>&hellip;More will be added after 3 seconds&hellip;</em></li>
</ol>


1
এটি নতুন DOM নোডের জন্য বেশ সুন্দরভাবে কাজ করছে বলে মনে হচ্ছে। ডোম নোড পরিবর্তনগুলি (কমপক্ষে ডোম নোডের মান / পাঠ্য?) হ্যান্ডেল করার জন্যও আমরা কী এটি গ্রহণ করতে পারি
সেবাস্তিয়ান লোরবার

8
@ সেবাস্তিয়ানলরবার - "আমরা" কে? আপনি, একজন প্রোগ্রামার হিসাবে, এই কোডটি নিতে এবং আপনার ইচ্ছামত ব্যবহার করতে পারেন। শুধু MDN এ পড়ুন আপনি কোন বিষয়গুলির জন্য DOM পর্যবেক্ষণ করতে পারেন এবং কোনটি আপনি পারবেন না।
vsync

2
mutations, observerআরও নিয়ন্ত্রণের জন্য কলব্যাক ফাংশনে পরামিতিগুলি পাস করুন ।
আরপুন

2
এটি আমাকে অনেক সাহায্য করেছে, তবে আমি কীভাবে এটি "আনবাইন্ড" করব? বলুন আমি একবারে পরিবর্তনটি দেখতে চাই, তবে একাধিক অনুষ্ঠানে এটি করবেন? oberserveDOM = নাল স্পষ্টতই কাজ করবে না ...
stiller_leser

কেন এটি কেবল সংযুক্ত / সরানোর জন্য কাজ করবে? দেখে মনে হচ্ছে মিউটেশন ইভেন্টগুলি এর চেয়ে বেশি cover
েকে আছে

15

আমি সম্প্রতি একটি প্লাগইন লিখেছি যা ঠিক তা করে - jquery.initialize

আপনি এটি .eachফাংশন হিসাবে একইভাবে ব্যবহার

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

পার্থক্যটি .eachহ'ল - এটি আপনার নির্বাচককে লাগে, .some-elementএক্ষেত্রে এবং ভবিষ্যতে এই নির্বাচকটির সাথে নতুন উপাদানগুলির জন্য অপেক্ষা করুন, যদি এই জাতীয় উপাদান যুক্ত করা হয় তবে এটিও শুরু করা হবে।

আমাদের ক্ষেত্রে ফাংশনটি আরম্ভ করুন কেবলমাত্র উপাদান রঙকে নীল করে দিন। সুতরাং আমরা যদি নতুন উপাদান যুক্ত করব (এজাক্স বা এমনকি এফ 12 ইন্সপেক্টর বা কোনও কিছুর সাথে নয়) যেমন:

$("<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- এটি রিডমি পৃষ্ঠায় বিস্তারিত হিসাবে নির্ভরতা সহ আইই 9 এবং 10 এ কাজ করবে ।


দয়া করে, এনপিএম এ যুক্ত করুন।
এক্সপ্রেস

14

অথবা আপনি কেবল নিজের ইভেন্ট তৈরি করতে পারেন যা সর্বত্র চালিত

 $("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/


এটি একই নয় ... উপরে বর্ণিত পদ্ধতিটি এখনও বৈধ api.jquery.com/trigger
লেফয়

11

এটি মজিলা থেকে মিউটেশনআবার্সবার ব্যবহার করে এই ব্লগ পোস্টটি থেকে অভিযোজিত একটি উদাহরণ

ক্রোম 18+, ফায়ারফক্স 14+, আইই 11+, সাফারি 6+

// Select the node that will be observed for mutations
var targetNode = document.getElementById('some-id');

// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true };

// Callback function to execute when mutations are observed
var callback = function(mutationsList) {
    for(var mutation of mutationsList) {
        if (mutation.type == 'childList') {
            console.log('A child node has been added or removed.');
        }
        else if (mutation.type == 'attributes') {
            console.log('The ' + mutation.attributeName + ' attribute was modified.');
        }
    }
};

// Create an observer instance linked to the callback function
var observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode, config);

// Later, you can stop observing
observer.disconnect();

4

ব্যবহার করুন MutationObserver ইন্টারফেস হিসেবে গ্যাব্রিয়েল Romanato এর দেখানো ব্লগ

ক্রোম 18+, ফায়ারফক্স 14+, আইই 11+, সাফারি 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();

3
মিউটেশনউসারভার নেটিভ জাভাস্ক্রিপ্ট, jQuery নয়।
বেনিয়ামিন

2

কিভাবে এই জন্য একটি 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*/ ) });

জিকিউরি ১.৯++ এর জন্য সমর্থন তৈরি করেছে (আমি শুনেছি পরীক্ষিত হয়নি)।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.