[ Web Proxy ]
URL:
Viewing: https://uz.javascript.info/mutation-observer [Back]  [Original]

Mutation observer
UZ

Ushbu ochiq manbali loyihani butun dunyo bo'ylab odamlar uchun taqdim etmoqchimiz.

Ushbu qo'llanmaning mazmuni sizning tilingizga tarjima qilishga yordam bering!

    Javascript.info saytidan qidirish:
    O'quv qo'llanmasidan qidiring:
    Light themeDark theme
    DanskEnglishEspaolFranaisIndonesiaItalianoTrkeOzbek

    MutationObserver bu DOM elementini kuzatuvchi va ozgarish aniqlanganida callback ishga tushiruvchi ichki obyekt.

    Avval sintaksisga qarab, keyin real foydalanish misolini organamiz va bunday narsa qayerda foydali bolishi mumkinligini koramiz.

    Sintaksis

    MutationObserver dan foydalanish oson.

    Birinchi, biz callback-funksiya bilan kuzatuvchi yaratamiz:

    let observer = new MutationObserver(callback);

    Songra uni DOM tuguniga boglaymiz:

    observer.observe(node, config);

    config bu qanday ozgarishlarga javob berish haqidagi boolean variantlar bilan obyekt:

    • childList node ning bevosita bolalarida ozgarishlar,
    • subtree node ning barcha avlodlarida,
    • attributes node ning atributlarida,
    • attributeFilter atribut nomlari massivi, faqat tanlanganlarini kuzatish uchun.
    • characterData node.data ni (matn mazmuni) kuzatish kerakmi,

    Boshqa variantlar:

    • attributeOldValue agar true bolsa, atributning eski va yangi qiymatini callback ga uzatadi (quyida koring), aks holda faqat yangisini (attributes varianti kerak),
    • characterDataOldValue agar true bolsa, node.data ning eski va yangi qiymatini callback ga uzatadi (quyida koring), aks holda faqat yangisini (characterData varianti kerak).

    Keyin har qanday ozgarishlardan song callback bajariladi: ozgarishlar birinchi argumentda MutationRecord obyektlari royxati sifatida, kuzatuvchining ozi ikkinchi argument sifatida uzatiladi.

    MutationRecord obyektlari quyidagi xususiyatlarga ega:

    • type mutatsiya turi, quyidagilardan biri:
      • "attributes": atribut ozgartirildi
      • "characterData": malumot ozgartirildi, matn tugunlari uchun ishlatiladi,
      • "childList": bola elementlar qoshildi/ochirildi,
    • target ozgarish qayerda sodir boldi: "attributes" uchun element, "characterData" uchun matn tuguni yoki "childList" mutatsiyasi uchun element,
    • addedNodes/removedNodes qoshilgan/ochirilgan tugunlar,
    • previousSibling/nextSibling qoshilgan/ochirilgan tugunlarning oldingi va keyingi qoshnilari,
    • attributeName/attributeNamespace ozgartirilgan atributning nomi/nomlar maydoni (XML uchun),
    • oldValue oldingi qiymat, faqat atribut yoki matn ozgarishlari uchun, agar mos variant ornatilgan bolsa attributeOldValue/characterDataOldValue.

    Masalan, mana contentEditable atributli <div>. Bu atribut bizga unga etibor qaratish va tahrirlash imkonini beradi.

    <div contentEditable id="elem">Bosing va <b>tahrirlang</b>, iltimos</div>
    
    <script>
    let observer = new MutationObserver(mutationRecords => {
      console.log(mutationRecords); // console.log(o'zgarishlar)
    });
    
    // atributlardan tashqari hammani kuzat
    observer.observe(elem, {
      childList: true, // bevosita bolalarni kuzat
      subtree: true, // pastki avlodlarni ham
      characterDataOldValue: true // eski ma'lumotni callback ga uzat
    });
    </script>

    Agar biz bu kodni brauzerda ishga tushirib, berilgan <div> ga etibor qaratib, <b>tahrirlang</b> ichidagi matnni ozgartirsak, console.log bitta mutatsiyani korsatadi:

    mutationRecords = [{
      type: "characterData",
      oldValue: "tahrirlang",
      target: <text node>,
      // boshqa xususiyatlar bo'sh
    }];

    Agar biz murakkabroq tahrirlash operatsiyalarini bajarsak, masalan <b>tahrirlang</b> ni ochirsak, mutatsiya hodisasi bir nechta mutatsiya yozuvlarini oz ichiga olishi mumkin:

    mutationRecords = [{
      type: "childList",
      target: <div#elem>,
      removedNodes: [<b>],
      nextSibling: <text node>,
      previousSibling: <text node>
      // boshqa xususiyatlar bo'sh
    }, {
      type: "characterData"
      target: <text node>
      // ...mutatsiya tafsilotlari brauzerning bunday o'chirishni qanday hal qilishiga bog'liq
      // u ikki qo'shni matn tugunlarini "tahrirlang " va ", iltimos" ni bitta tugunga birlashtirishi mumkin
      // yoki ularni alohida matn tugunlari sifatida qoldirishi mumkin
    }];

    Demak, MutationObserver DOM pastdaraxtidagi har qanday ozgarishlarga javob berish imkonini beradi.

    Integratsiya uchun foydalanish

    Bunday narsa qachon foydali bolishi mumkin?

    Foydali funksiyani oz ichiga olgan, lekin ayni paytda keraksiz narsalarni, masalan reklamalarni <div class="ads">Keraksiz reklamalar</div> korsatadigan uchinchi tomon skriptini qoshishingiz kerak bolgan vaziyatni tasavvur qiling.

    Tabiiyki, uchinchi tomon skripti uni ochirish uchun hech qanday mexanizm bermaydi.

    MutationObserver dan foydalanib, keraksiz element bizning DOM da paydo bolganini aniqlab, uni ochirishimiz mumkin.

    Uchinchi tomon skripti bizning hujjatimizga biror narsa qoshadigan va biz buni aniqlamoqchi bolgan, sahifamizni moslashtiramiz, dinamik ravishda biror narsani olchamini ozgartiramiz va hokazolar qiladigan boshqa vaziyatlar ham bor.

    MutationObserver buni amalga oshirish imkonini beradi.

    Arxitektura uchun foydalanish

    MutationObserver arxitektura nuqtayi nazaridan yaxshi bolgan vaziyatlar ham bor.

    Aytaylik, biz dasturlash haqida veb-sayt yaratyapmiz. Tabiiyki, maqolalar va boshqa materiallar kod qisqichlarini oz ichiga olishi mumkin.

    HTML belgilashda bunday qisqich quyidagicha korinadi:

    ...
    <pre class="language-javascript"><code>
      // mana kod
      let hello = "world";
    </code></pre>
    ...

    Yaxshiroq oqilishi va ayni paytda uni chiroylashtiramiz uchun saytimizda JavaScript sintaksis takidlash kutubxonasidan, masalan Prism.js dan foydalanamiz. Yuqoridagi qisqich uchun Prism da sintaksis takidlashni olish uchun Prism.highlightElem(pre) chaqiriladi, bu bunday pre elementlarining mazmunini tekshiradi va rangli sintaksis takidlash uchun maxsus teglar va stillarni qoshadi, xuddi bu sahifadagi misollarda korganingizdek.

    Aynan qachon bu takidlash usulini ishga tushirishimiz kerak? Biz buni DOMContentLoaded hodisasida qilishimiz yoki skriptni sahifaning pastki qismiga qoyishimiz mumkin. DOM tayyor bolgan paytda biz pre[class*="language"] elementlarini qidiribo, ularga Prism.highlightElem chaqirishimiz mumkin:

    // sahifadagi barcha kod qisqichlarini ta'kidlash
    document.querySelectorAll('pre[class*="language"]').forEach(Prism.highlightElem);

    Hozircha hammasi oddiy, shunday emasmi? Biz HTML da kod qisqichlarini topamiz va ularni takidlaymiz.

    Endi davom etaylik. Aytaylik, biz serverdan dinamik ravishda materiallarni yuklamoqchimiz. Buning usullarini keyinroq organamiz. Hozir faqat veb-serverdan HTML maqola yuklab, uni talab boyicha korsatishimiz muhim:

    let article = /* serverdan yangi kontent yuklash */
    articleElem.innerHTML = article;

    Yangi article HTML kod qisqichlarini oz ichiga olishi mumkin. Ularga Prism.highlightElem chaqirishimiz kerak, aks holda ular takidlanmaydi.

    Dinamik yuklangan maqola uchun Prism.highlightElem ni qayerda va qachon chaqirish kerak?

    Biz bu chaqiruvni maqola yuklaydigan kodga qoshishimiz mumkin:

    let article = /* serverdan yangi kontent yuklash */
    articleElem.innerHTML = article;
    
    let snippets = articleElem.querySelectorAll('pre[class*="language-"]');
    snippets.forEach(Prism.highlightElem);

    Lekin tasavvur qiling, kodda kontent yuklaydigan kop joylar bor maqolalar, viktorinalar, forum postlari va hokazo. Takidlash chaqiruvini har yerga qoyishimiz kerakmi, yuklagandan keyin kontentdagi kodni takidlash uchun? Bu unchalik qulay emas.

    Va agar kontent uchinchi tomon moduli tomonidan yuklanayotgan bolsa-chi? Masalan, bizda kimdir tomonidan yozilgan, kontentni dinamik yuklaydigaan forum bor va biz unga sintaksis takidlashni qoshmoqchimiz. Hech kim uchinchi tomon skriptlarini yamoqlashni yoqtirmaydi.

    Yaxshiyamki, boshqa variant bor.

    Biz kod qisqichlari sahifaga qoshilganini avtomatik aniqlash va ularni takidlash uchun MutationObserver dan foydalanishimiz mumkin.

    Shunday qilib biz takidlash funksiyasini bir joyda boshqaramiz, uni integratsiya qilish ehtiyojidan xalos bolamiz.

    Dinamik takidlash namoyishi

    Mana ishlaydigan misol.

    Agar siz bu kodni ishga tushirsangiz, u quyidagi elementni kuzata boshlaydi va u yerda paydo boladigan har qanday kod qisqichlarini takidlaydi:

    let observer = new MutationObserver(mutations => {
    
      for(let mutation of mutations) {
        // yangi tugunlarni tekshir, ta'kidlanadigan narsa bormi?
    
        for(let node of mutation.addedNodes) {
          // faqat elementlarni kuzatamiz, boshqa tugunlarni (masalan matn tugunlarini) o'tkazib yuboramiz
          if (!(node instanceof HTMLElement)) continue;
    
          // qo'shilgan elementni kod qisqichi ekanligini tekshir
          if (node.matches('pre[class*="language-"]')) {
            Prism.highlightElement(node);
          }
    
          // yoki uning pastdaraxtida kod qisqichi bormi?
          for(let elem of node.querySelectorAll('pre[class*="language-"]')) {
            Prism.highlightElement(elem);
          }
        }
      }
    
    });
    
    let demoElem = document.getElementById('highlight-demo');
    
    observer.observe(demoElem, {childList: true, subtree: true});

    Bu yerda, pastda HTML-element va uni innerHTML yordamida dinamik toldiradigan JavaScript bor.

    Iltimos, oldingi kodni ishga tushiring (yuqorida, u elementni kuzatadi), keyin quyidagi kodni. MutationObserver qisqichni qanday aniqlab, takidlashini korasiz.

    Quyidagi kod uning innerHTML ni toldiradi, bu MutationObserver ning javob berishiga va mazmunini takidlashiga sabab boladi:

    let demoElem = document.getElementById('highlight-demo');
    
    // kod qisqichlari bilan kontentni dinamik qo'shish
    demoElem.innerHTML = `Quyida kod qisqichi bor:
      <pre class="language-javascript"><code> let hello = "world!"; </code></pre>
      <div>Yana biri:</div>
      <div>
        <pre class="language-css"><code>.class { margin: 5px; } </code></pre>
      </div>
    `;

    Endi bizda kuzatiladigan elementlar yoki butun document da barcha takidlashlarni kuzata oladigan MutationObserver bor. Biz bu haqida oylamasdan HTML da kod qisqichlarini qoshish/ochirish mumkin.

    Qoshimcha usullar

    Tugunni kuzatishni toxtatish usuli mavjud:

    • observer.disconnect() kuzatishni toxtatadi.

    Kuzatishni toxtatganimizda, bazi ozgarishlar hali kuzatuvchi tomonidan qayta ishlanmagan bolishi mumkin. Bunday hollarda biz quyidagini ishlatamiz:

    • observer.takeRecords() qayta ishlanmagan mutatsiya yozuvlari royxatini oladi sodir bolgan, lekin callback ularni hal qilmagan.

    Bu usullarni birgalikda ishlatish mumkin:

    // qayta ishlanmagan mutatsiyalar ro'yxatini olish
    // uzishdan oldin chaqirilishi kerak,
    // agar yaqinda hal qilinmagan mutatsiyalar haqida qayg'ursangiz
    let mutationRecords = observer.takeRecords();
    
    // o'zgarishlarni kuzatishni to'xtat
    observer.disconnect();
    ...

    observer.takeRecords() tomonidan qaytarilgan yozuvlar qayta ishlash navbatidan ochiriladi Callback observer.takeRecords() tomonidan qaytarilgan yozuvlar uchun chaqirilmaydi.

    Axlat yigish bilan ozaro tasir Kuzatuvchilar ichkarida tugunlarga zaif havolalardan foydalanadi. Yani, agar tugun DOM dan ochirilsa va erishib bolmaydigan bolsa, u axlat yigilishi mumkin.

    DOM tuguni kuzatilayotgani axlat yigishning oldini olmaydi.

    Xulosa

    MutationObserver DOM dagi ozgarishlarga javob bera oladi atributlar, matn mazmuni va elementlar qoshish/ochirish.

    Biz uni kodimizning boshqa qismlari tomonidan kiritilgan ozgarishlarni kuzatish, shuningdek uchinchi tomon skriptlari bilan integratsiya qilish uchun ishlatishimiz mumkin.

    MutationObserver har qanday ozgarishlarni kuzata oladi. Nimani kuzatish konfiguratsiya variantlari keraksiz callback chaqiruvlariga resurs sarflamaslik uchun optimallashtirishlar uchun ishlatiladi.

    O'quv qo'llanma xaritasi

    Izohlar

    izoh berishdan oldin buni o'qing
    • Agar sizda nimani yaxshilash kerakligi haqida takliflaringiz bo'lsa - iltimos, GitHub muammosini yuboring yoki izoh berish o'rniga so'rov yuboring.
    • Agar siz maqolada biror narsani tushunolmasangiz - iltimos, batafsilroq ma'lumot bering.
    • Bir nechta so'z so'zlarini kiritish uchun <code> yorlig'ini ishlating, bir nechta satrlar uchun - ularni <pre> yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepen)

    Web Proxy Viewer  |  New URL  |  Original Page