পৃষ্ঠায় কোনও উপাদান যুক্ত করা হলে কীভাবে আমাকে জানানো হবে?


139

পৃষ্ঠায় যখন কোনও ডিওএম উপাদান যুক্ত করা হয় তখন আমি আমার চয়ন করার একটি ফাংশন চাই। এটি ব্রাউজার এক্সটেনশনের প্রসঙ্গে, সুতরাং ওয়েবপৃষ্ঠাটি আমার থেকে স্বাধীনভাবে চলে এবং আমি এর উত্সটি পরিবর্তন করতে পারি না। এখানে আমার বিকল্পগুলি কি?

আমার ধারণা, তাত্ত্বিকভাবে, আমি কেবলমাত্র setInterval()উপাদানটির উপস্থিতির জন্য ক্রমাগত অনুসন্ধান করতে এবং উপাদান উপস্থিত থাকলে আমার ক্রিয়া সম্পাদন করতে পারি, তবে আমার আরও ভাল পদ্ধতির প্রয়োজন।


আপনি কি কোনও নির্দিষ্ট উপাদানের জন্য আপনার অন্য লিপিটি পৃষ্ঠাতে রেখেছেন বা কোনও উপাদানই উত্স হিসাবে বিবেচনা করে যুক্ত করা কোনও উপাদান যাচাই করতে হবে?
জোসে ফেইটি

1
আপনি কি জানেন যে কোন ফাংশন কারওর কোডে উপাদান যুক্ত করে, যদি আপনি এটি ওভাররাইট করতে পারেন এবং একটি কাস্টম ইভেন্ট ট্রিগার করার জন্য একটি অতিরিক্ত লাইন যুক্ত করতে পারেন?
জেফ্রেদেব

উত্তর:


86

সতর্কবাণী!

এই উত্তরটি এখন পুরানো। ডিওএম লেভেল 4 মিউটেশনঅবার্সার প্রবর্তন করেছিল, অবহিত মিউটেশন ইভেন্টগুলির কার্যকর প্রতিস্থাপন সরবরাহ করে। এই উত্তরটি এখানে উপস্থাপিত উত্তরের চেয়ে আরও ভাল সমাধানের জন্য দেখুন । সিরিয়াসলি। প্রতি 100 মিলিসেকেন্ডে ডোমকে পোল করবেন না; এটি সিপিইউ শক্তি অপচয় করবে এবং আপনার ব্যবহারকারীরা আপনাকে ঘৃণা করবে।

যেহেতু ২০১২ সালে মিউটেশন ইভেন্টগুলি অবহেলা করা হয়েছিল এবং theোকানো উপাদানগুলির উপর আপনার কোনও নিয়ন্ত্রণ নেই কারণ এগুলি অন্য কারও কোড দ্বারা যুক্ত করা হয়েছে, আপনার একমাত্র বিকল্পটি অবিরত তাদের জন্য পরীক্ষা করা।

function checkDOMChange()
{
    // check for any new element being inserted here,
    // or a particular node being modified

    // call the function again after 100 milliseconds
    setTimeout( checkDOMChange, 100 );
}

একবার এই ফাংশনটি বলা হয়ে গেলে, এটি প্রতি 100 মিলিসেকেন্ডে চালিত হবে, যা সেকেন্ডের 1/10 (এক দশমাংশ)। আপনার রিয়েল-টাইম উপাদান পর্যবেক্ষণের প্রয়োজন না থাকলে এটি পর্যাপ্ত হওয়া উচিত।


1
জোস, শর্তটি আসলে পূরণ হলে আপনি কীভাবে আপনার সেটটাইমআউটটি শেষ করবেন? অর্থাৎ, আপনি এমন উপাদানটি খুঁজে পেয়েছেন যা শেষ পর্যন্ত আপনার পৃষ্ঠায় x সেকেন্ড পরে লোড করেছে?
ক্লিভিস

1
@ ব্লাচউক আপনাকে একটি ভেরিয়েবলের জন্য সেটটাইমআউট রিটার্ন মান প্রদান করতে হবে, যা আপনি পরে এটি পরিষ্কার করার জন্য প্যারামিটার হিসাবে ক্লিয়ারটাইমআউট () এ পাস করতে পারেন।
জোসে ফেটি

3
@ ব্ল্যাকহক: আমি কেবল উত্তরটি দেখেছি এবং এটি +1 করেছি; তবে আপনি সচেতন থাকবেন যে আপনার এখানে আসলে ক্লিয়ারটাইমআউট () ব্যবহার করার দরকার নেই, যেহেতু সেটটাইমআউট () কেবল একবার চালানো হয়! একটি 'যদি-অন্য' কেবলমাত্র পর্যাপ্ত: একবার theোকানো উপাদানটি পেয়ে গেলে সেটটাইমআউট () এ এক্সিকিউশনটি পাস করতে দেবেন না।
1111161171159459134

ব্যবহারের জন্য একটি কার্যকর ব্যবহারিক গাইড MutationObserver(): ডেভিডওয়ালশ.নেম
মিউটিউবেসারভার-

4
এটা নোংরা। আসলেই এএস 3 এর কোনও "সমতুল্য" নেই Event.ADDED_TO_STAGE?
বিটারব্লু

45

আসল উত্তরটি হ'ল "মিউটেশন পর্যবেক্ষকগুলি ব্যবহার করুন" (এই প্রশ্নে বর্ণিত হিসাবে: একটি এইচটিএমএল উপাদানটি ডমটিতে গতিশীলভাবে যুক্ত করা হয়েছে কিনা তা নির্ধারণ করা ) তবে সমর্থন (বিশেষত আইই তে) সীমাবদ্ধ ( http://caniuse.com/mutesobserver ) ।

সুতরাং আসল বাস্তব উত্তরটি হ'ল "মিউটেশন পর্যবেক্ষকগুলি ব্যবহার করুন .... অবশেষে But তবে আপাতত জোসে ফেটির উত্তরটি দিয়ে যান" :)


19

মধ্যবর্তী থামিয়ে দেওয়া পরিব্যক্তি ঘটনা এবং উত্থান MutationObserverযখন কোনও নির্দিষ্ট উপাদানের করে DOM করতে ছিল যোগ করা হয়েছে, একটি efficent পথ ঘোষিত হতে সিএসএস 3 অ্যানিমেশন ঘটনা কাজে লাগান

ব্লগ পোস্টটি উদ্ধৃত করতে:

একটি সিএসএস কীফ্রেম সিক্যুয়েন্স সেটআপ করুন যা লক্ষ্য করে (আপনার সিএসএস সিলেক্টরের পছন্দ অনুসারে) আপনি যে কোনও ডিওএম উপাদানগুলির জন্য ডিওএম নোড সন্নিবেশ ইভেন্ট পেতে চান। আমি তুলনামূলকভাবে সৌম্যযুক্ত এবং সামান্য ব্যবহৃত সিএসএস সম্পত্তি ব্যবহার করেছি , ক্লিপ আমি লক্ষ্যবস্তু পৃষ্ঠা শৈলীর সাথে জগাখিচুড়ি এড়ানোর প্রয়াসে আউটলাইন-রঙ ব্যবহার করেছি - কোডটি একবার ক্লিপ সম্পত্তিটিকে লক্ষ্যবস্তু করেছিল, তবে এটি ১১ সংস্করণ অনুসারে আইআই তে আর অ্যানিমেটেবল নয় That বলেছিলেন, অ্যানিমেটেড করা যায় এমন যে কোনও সম্পত্তি কাজ করবে, আপনার পছন্দের যেকোন একটি চয়ন করুন।

এরপরে আমি নথ সন্নিবেশ প্রক্রিয়াকরণের জন্য একটি প্রতিনিধি হিসাবে ব্যবহার করি এমন একটি ডকুমেন্ট-প্রশস্ত অ্যানিমেশন স্টার্ট শ্রোতা যুক্ত করেছি। অ্যানিমেশন ইভেন্টটিতে অ্যানিমেশননাম নামে একটি সম্পত্তি রয়েছে যা আপনাকে জানায় যে কোন কীফ্রেম সিকোয়েন্সটি অ্যানিমেশনটি বন্ধ করে দিয়েছে। কেবল নিশ্চিত হয়ে নিন যে অ্যানিমেশননাম সম্পত্তিটি নোড সন্নিবেশের জন্য আপনি যে কীফ্রেম সিক্যুয়েন্স নামের যুক্ত করেছেন ঠিক একইরকম এবং আপনি যেতে ভাল।


এটি সর্বোচ্চ-পারফরম্যান্স সমাধান এবং এর জন্য একটি লাইব্রেরির উল্লেখ করে একটি সদৃশ প্রশ্নের একটি উত্তর রয়েছে
ড্যান ড্যাসক্লেস্কু

1
আন্ডাররেটেড উত্তর।
গোখন কুর্ট

সাবধান হন। যদি মিলিসেকেন্ড যথাযথতা গুরুত্বপূর্ণ হয় তবে এই পদ্ধতির সঠিক থেকে দূরে। এই jsbin দেখায় যে একটি ইনলাইন কলব্যাক এবং ব্যবহার animationstart, jsbin.com/netuquralu/1/edit এর মধ্যে 30ms এরও বেশি পার্থক্য রয়েছে ।
গজুস

আমি কার্টের সাথে একমত, এটি আন্ডাররেটেড।
জাববু

13

আপনি livequeryjQuery জন্য প্লাগইন ব্যবহার করতে পারেন । আপনি একটি নির্বাচক মত প্রকাশ করতে পারেন যেমন:

$("input[type=button].removeItemButton").livequery(function () {
    $("#statusBar").text('You may now remove items.');
});

প্রতিবার একটি বোতাম removeItemButton ক্লাসের যুক্ত হওয়ার সাথে সাথে একটি বার্তা স্ট্যাটাস বারে উপস্থিত হয়।

দক্ষতার দিক থেকে আপনি এটি এড়াতে চাইতে পারেন, তবে যে কোনও ক্ষেত্রে আপনি নিজের ইভেন্ট হ্যান্ডলার তৈরি করার পরিবর্তে প্লাগইনটি লাভ করতে পারেন।

পুনরায় দেখা উত্তর

উপরের উত্তরটির অর্থ কেবল এটি সনাক্ত করা ছিল যে কোনও আইটেম ডিওমে যুক্ত করা হয়েছে প্লাগইন মাধ্যমে।

তবে, সম্ভবত, একটি jQuery.on()পদ্ধতির আরও উপযুক্ত হবে, উদাহরণস্বরূপ:

$("#myParentContainer").on('click', '.removeItemButton', function(){
          alert($(this).text() + ' has been removed');
});

আপনার যদি ডায়নামিক সামগ্রী থাকে যা ক্লিকগুলিতে প্রতিক্রিয়া জানায় উদাহরণস্বরূপ, ইভেন্টগুলি পিতামাতার সাথে ব্যবহার করে ভাল ব্যবহার করা ভাল jQuery.on


11

ETA 24 এপ্রিল 17 আমি কিছু async/ এর সাহায্যে এটিকে কিছুটা সহজ করতে চেয়েছিলামawait যাদুতে এটি , কারণ এটি এটিকে অনেক বেশি সংহত করে তোলে:

একই প্রতিশ্রুতিবদ্ধ-পর্যবেক্ষণযোগ্য ব্যবহার করে:

const startObservable = (domNode) => {
  var targetNode = domNode;

  var observerConfig = {
    attributes: true,
    childList: true,
    characterData: true
  };

  return new Promise((resolve) => {
      var observer = new MutationObserver(function (mutations) {
         // For the sake of...observation...let's output the mutation to console to see how this all works
         mutations.forEach(function (mutation) {
             console.log(mutation.type);
         });
         resolve(mutations)
     });
     observer.observe(targetNode, observerConfig);
   })
} 

আপনার কলিং ফাংশন যেমন সহজ হতে পারে:

const waitForMutation = async () => {
    const button = document.querySelector('.some-button')
    if (button !== null) button.click()
    try {
      const results = await startObservable(someDomNode)
      return results
    } catch (err) { 
      console.error(err)
    }
}

আপনি যদি একটি সময়সীমা যুক্ত করতে চান, আপনি এখানে প্রদর্শিত হিসাবে একটি সাধারণ Promise.raceপ্যাটার্ন ব্যবহার করতে পারেন :

const waitForMutation = async (timeout = 5000 /*in ms*/) => {
    const button = document.querySelector('.some-button')
    if (button !== null) button.click()
    try {

      const results = await Promise.race([
          startObservable(someDomNode),
          // this will throw after the timeout, skipping 
          // the return & going to the catch block
          new Promise((resolve, reject) => setTimeout(
             reject, 
             timeout, 
             new Error('timed out waiting for mutation')
          )
       ])
      return results
    } catch (err) { 
      console.error(err)
    }
}

মূল

আপনি এটি লাইব্রেরি ছাড়াই করতে পারেন, তবে আপনাকে কিছু ES6 জিনিস ব্যবহার করতে হবে, সুতরাং সামঞ্জস্যতার বিষয়ে সচেতন হতে হবে (যেমন, আপনার শ্রোতা যদি বেশিরভাগ ক্ষেত্রে আমিশ, লুডাইট বা খারাপ, আই 88 ব্যবহারকারী হন)

প্রথমত, আমরা একটি পর্যবেক্ষক অবজেক্ট তৈরি করতে মিউটেশনউসারভার এপিআই ব্যবহার করব । আমরা এই বস্তুকে একটি প্রতিশ্রুতিতে resolve()আবদ্ধ করব, এবং কলব্যাকটি বহিস্কার হওয়ার পরে (এইচ / টি ডেভিডওয়ালশব্লগ) ডেভিড ওয়ালশ ব্লগ নিবন্ধে মিউটেশনগুলি :

const startObservable = (domNode) => {
    var targetNode = domNode;

    var observerConfig = {
        attributes: true,
        childList: true,
        characterData: true
    };

    return new Promise((resolve) => {
        var observer = new MutationObserver(function (mutations) {
            // For the sake of...observation...let's output the mutation to console to see how this all works
            mutations.forEach(function (mutation) {
                console.log(mutation.type);
            });
            resolve(mutations)
        });
        observer.observe(targetNode, observerConfig);
    })
} 

তারপরে, আমরা একটি তৈরি করব generator function। আপনি যদি এগুলি এখনও ব্যবহার না করে থাকেন তবে আপনি মিস করছেন - তবে একটি সংক্ষিপ্ত প্রতিশব্দটি হ'ল: এটি একটি সিঙ্ক ফাংশনের মতো চলে এবং যখন এটি কোনও yield <Promise>অভিব্যক্তি খুঁজে পায় , তখন প্রতিশ্রুতি হওয়ার জন্য এটি একটি অবরুদ্ধ ফ্যাশনে অপেক্ষা করে পরিপূর্ণ ( জেনারেটরগুলি এর চেয়ে বেশি কিছু করে, তবে আমরা এখানে আগ্রহী এটিই )।

// we'll declare our DOM node here, too
let targ = document.querySelector('#domNodeToWatch')

function* getMutation() {
    console.log("Starting")
    var mutations = yield startObservable(targ)
    console.log("done")
}

জেনারেটর সম্পর্কে একটি জটিল অংশ হ'ল তারা কোনও সাধারণ ফাংশনের মতো 'রিটার্ন' করে না। সুতরাং, আমরা নিয়মিত ফাংশনের মতো জেনারেটর ব্যবহার করতে সক্ষম হতে একটি সহায়ক ফাংশন ব্যবহার করব। (আবার, hw / to dwb )

function runGenerator(g) {
    var it = g(), ret;

    // asynchronously iterate over generator
    (function iterate(val){
        ret = it.next( val );

        if (!ret.done) {
            // poor man's "is it a promise?" test
            if ("then" in ret.value) {
                // wait on the promise
                ret.value.then( iterate );
            }
            // immediate value: just send right back in
            else {
                // avoid synchronous recursion
                setTimeout( function(){
                    iterate( ret.value );
                }, 0 );
            }
        }
    })();
}

তারপরে, প্রত্যাশিত DOM রূপান্তর ঘটার আগে যে কোনও মুহুর্তে, কেবল চালান runGenerator(getMutation)

এখন আপনি একটি সিঙ্ক্রোনাস স্টাইল নিয়ন্ত্রণ প্রবাহে DOM রূপান্তর একীভূত করতে পারেন। কি যে বিস্ময়কর।


8

অ্যারাইভ নামে একটি প্রতিশ্রুতিবদ্ধ জাভাস্ক্রিপ্ট লাইব্রেরি রয়েছে যা ব্রাউজার সমর্থন সাধারণ হয়ে যাওয়ার পরে মিউটেশন পর্যবেক্ষকদের সুবিধা নেওয়া শুরু করার দুর্দান্ত উপায় বলে মনে হচ্ছে।

https://github.com/uzairfarooq/arrive/


3

এই প্লাগইনটি পরীক্ষা করে দেখুন যা এটি সুনির্দিষ্টভাবে করে না - jquery.initialize

এটি প্রতিটি ফাংশনের মতো সুস্পষ্টভাবে কাজ করে, পার্থক্যটি হ'ল আপনি নির্বাচিত নির্বাচিত হয়েছিলেন এবং ভবিষ্যতে এই নির্বাচকের সাথে মিলে যাওয়া নতুন আইটেমগুলি দেখুন এবং তাদের সূচনা করুন

এর মতো দেখতে শুরু করুন

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

তবে এখন যদি নতুন উপাদান মেলে .some-element নির্বাচক পৃষ্ঠাটিতে উপস্থিত হয় তবে তা তাত্ক্ষণিকভাবে শুরু করা হবে।

নতুন আইটেমটি যুক্ত করার উপায়টি গুরুত্বপূর্ণ নয়, আপনাকে কোনও কলব্যাক ইত্যাদির যত্ন নেওয়া দরকার না etc.

সুতরাং আপনি যদি নতুন উপাদান যুক্ত করতে চান তবে:

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

এটি তাত্ক্ষণিকভাবে শুরু করা হবে।

প্লাগইন উপর ভিত্তি করে MutationObserver


0

একটি খাঁটি জাভাস্ক্রিপ্ট সমাধান (ছাড়াই jQuery):

const SEARCH_DELAY = 100; // in ms

// it may run indefinitely. TODO: make it cancellable, using Promise's `reject`
function waitForElementToBeAdded(cssSelector) {
  return new Promise((resolve) => {
    const interval = setInterval(() => {
      if (element = document.querySelector(cssSelector)) {
        clearInterval(interval);
        resolve(element);
      }
    }, SEARCH_DELAY);
  });
}

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