มีผู้ฟังการเปลี่ยนแปลง JavaScript / jQuery DOM หรือไม่


402

เป็นหลักฉันต้องการให้สคริปต์ทำงานเมื่อเนื้อหาของการDIVเปลี่ยนแปลง เนื่องจากสคริปต์นั้นแยกจากกัน (สคริปต์เนื้อหาในส่วนขยายของ Chrome & สคริปต์หน้าเว็บ) ฉันต้องการวิธีการเพียงสังเกตการเปลี่ยนแปลงในสถานะ DOM ฉันสามารถตั้งค่าการลงคะแนนเลือกตั้งได้ แต่นั่นดูไม่เลอะเทอะ

คำตอบ:


488

เป็นเวลานานเหตุการณ์การกลายพันธุ์ของ DOM3 เป็นวิธีแก้ปัญหาที่ดีที่สุด แต่ก็ไม่ได้รับการสนับสนุนด้วยเหตุผลด้านประสิทธิภาพ ผู้สังเกตการณ์การเปลี่ยนแปลง DOM4เป็นการแทนที่เหตุการณ์การกลายพันธุ์ DOM3 ที่เลิกใช้แล้ว ขณะนี้มีการใช้งานในเบราว์เซอร์ที่ทันสมัยในฐานะMutationObserver(หรือตามที่ผู้ขายนำหน้าWebKitMutationObserverไว้ใน Chrome เวอร์ชันเก่า):

MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

var observer = new MutationObserver(function(mutations, observer) {
    // fired when a mutation occurs
    console.log(mutations, observer);
    // ...
});

// define what element should be observed by the observer
// and what types of mutations trigger the callback
observer.observe(document, {
  subtree: true,
  attributes: true
  //...
});

ตัวอย่างนี้รับฟังการเปลี่ยนแปลงของ DOM documentและทรีย่อยทั้งหมดและจะเริ่มต้นการเปลี่ยนแปลงคุณลักษณะขององค์ประกอบรวมถึงการเปลี่ยนแปลงโครงสร้าง ข้อมูลจำเพาะฉบับร่างมีรายการคุณสมบัติการฟังการกลายพันธุ์ที่ถูกต้องทั้งหมด:

childList

  • ตั้งค่าเป็นtrueหากต้องคอยสังเกตการกลายพันธุ์ของลูกเป้าหมาย

คุณลักษณะ

  • ตั้งค่าเป็นtrueหากจะทำการสังเกตการกลายพันธุ์ของแอททริบิวของเป้าหมาย

characterData

  • ตั้งค่าเป็นtrueหากจะทำการตรวจสอบการกลายพันธุ์ของข้อมูลเป้าหมาย

ทรีย่อย

  • ตั้งค่าเป็นtrueหากการกลายพันธุ์ไม่ได้เป็นเพียงเป้าหมาย แต่ยังต้องปฏิบัติตามการสืบทอดของเป้าหมายด้วย

attributeOldValue

  • ตั้งเป็นtrueหากattributesถูกตั้งค่าเป็นจริงและค่าแอตทริบิวต์ของเป้าหมายก่อนที่จะต้องมีการบันทึกการกลายพันธุ์

characterDataOldValue

  • ตั้งค่าเป็นtrueหากcharacterDataถูกตั้งค่าเป็นจริงและข้อมูลของเป้าหมายก่อนที่จะต้องมีการบันทึกการกลายพันธุ์

attributeFilter

  • ตั้งค่าเป็นรายการของชื่อโลคัลแอ็ตทริบิวต์ (ไม่มีเนมสเปซ) หากไม่จำเป็นต้องปฏิบัติตามการกลายพันธุ์ของแอ็ตทริบิวต์ทั้งหมด

(รายการนี้เป็นปัจจุบัน ณ เดือนเมษายน 2014 คุณสามารถตรวจสอบข้อกำหนดสำหรับการเปลี่ยนแปลงใด ๆ )


3
@AshrafBashir ฉันเห็นตัวอย่างการทำงานที่ดีใน Firefox 19.0.2: ฉันเห็น([{}])เข้าสู่คอนโซลซึ่งแสดงให้เห็นถึงความคาดหวังMutationRecordเมื่อฉันคลิกที่มัน โปรดตรวจสอบอีกครั้งเนื่องจากอาจเป็นความล้มเหลวทางเทคนิคชั่วคราวใน JSFiddle ฉันยังไม่ได้ทดสอบใน IE เนื่องจากฉันยังไม่มี IE 10 ซึ่งปัจจุบันเป็นรุ่นเดียวที่รองรับเหตุการณ์การกลายพันธุ์
apsillers

1
ฉันเพิ่งโพสต์คำตอบที่ทำงานใน IE10 + และส่วนใหญ่เป็นอย่างอื่น
naugtur

1
ข้อมูลจำเพาะดูเหมือนจะไม่มีกล่องสีเขียวที่แสดงรายการตัวเลือกผู้สังเกตการณ์การกลายพันธุ์อีกต่อไป มันแสดงรายการตัวเลือกในส่วน 5.3.1 และอธิบายเพียงเล็กน้อยด้านล่าง
LS

2
@ LS ขอบคุณฉันได้อัปเดตลิงก์แล้วลบบิตเกี่ยวกับกล่องสีเขียวและแก้ไขรายการทั้งหมดลงในคำตอบของฉัน (ในกรณีที่การเชื่อมโยงในอนาคตเน่า)
apsillers


211

แก้ไข

คำตอบนี้เลิกใช้แล้ว ดูคำตอบโดยapsillers

เนื่องจากนี่เป็นส่วนขยายของ Chrome คุณจึงอาจใช้กิจกรรม DOM มาตรฐานDOMSubtreeModifiedเช่นกัน ดูการสนับสนุนกิจกรรมนี้ผ่านเบราว์เซอร์ Chrome ได้รับการสนับสนุนตั้งแต่ 1.0

$("#someDiv").bind("DOMSubtreeModified", function() {
    alert("tree changed");
});

ดูตัวอย่างการทำงานที่นี่


ฉันสังเกตเห็นว่าเหตุการณ์นี้สามารถยิงได้แม้หลังจากตัวเลือกบางอย่าง ฉันกำลังตรวจสอบ
Peder Rice

9
w3.org/TR/DOM-Level-3-Events/#event-type-DOMSubtreeModifiedกล่าวว่ากิจกรรมนี้เลิกใช้แล้วเราจะใช้อะไรแทน
Maslow

2
@ Maslow- ยังไม่มี! stackoverflow.com/questions/6659662/...
แซม Rueby

4
มีgithub.com/joelpurra/jquery-mutation-summaryซึ่งโดยทั่วไปจะแก้ปัญหาให้กับผู้ใช้ jquery
Capi Etheriel

1
ยังใช้งานได้หากคุณกำลังสร้างส่วนขยายของ Chrome ล้ำค่า.
แนวคิด 47

49

เว็บไซต์หลายแห่งใช้ AJAX เพื่อเพิ่ม / แสดง / เปลี่ยนเนื้อหาแบบไดนามิก บางครั้งใช้แทนการนำทางภายในไซต์ดังนั้น URL ปัจจุบันจึงเปลี่ยนไปทางโปรแกรมและสคริปต์เนื้อหาจะไม่ถูกเรียกใช้งานโดยเบราว์เซอร์ในกรณีนี้โดยอัตโนมัติเนื่องจากหน้าเว็บไม่ได้รับข้อมูลจากเซิร์ฟเวอร์ระยะไกลทั้งหมด


วิธี JS ปกติของการตรวจสอบหน้าการเปลี่ยนแปลงที่มีอยู่ในสคริปต์เนื้อหา


ส่วนขยายเฉพาะ: ตรวจสอบการเปลี่ยนแปลง URL ในพื้นหลัง / หน้ากิจกรรม

มี API ขั้นสูงเพื่อการทำงานที่มีระบบนำทางคือ: webNavigation , WebRequestแต่เราจะใช้ง่ายchrome.tabs.onUpdatedฟังเหตุการณ์ที่ส่งข้อความไปยังสคริปต์เนื้อหา:

  • manifest.json:
    ประกาศพื้นหลังหน้า / เหตุการณ์
    ประกาศเนื้อหาสคริปต์
    เพิ่มได้รับอนุญาต"tabs"

  • background.js

    var rxLookfor = /^https?:\/\/(www\.)?google\.(com|\w\w(\.\w\w)?)\/.*?[?#&]q=/;
    chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
        if (rxLookfor.test(changeInfo.url)) {
            chrome.tabs.sendMessage(tabId, 'url-update');
        }
    });
  • content.js

    chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
        if (msg === 'url-update') {
            doSomething();
        }
    });

29

วิธีการอื่นขึ้นอยู่กับว่าคุณกำลังเปลี่ยน div หากคุณใช้ JQuery เพื่อเปลี่ยนเนื้อหาของ div ด้วยวิธี html () คุณสามารถขยายวิธีนั้นและเรียกใช้ฟังก์ชันการลงทะเบียนทุกครั้งที่คุณใส่ html ใน div

(function( $, oldHtmlMethod ){
    // Override the core html method in the jQuery object.
    $.fn.html = function(){
        // Execute the original HTML method using the
        // augmented arguments collection.

        var results = oldHtmlMethod.apply( this, arguments );
        com.invisibility.elements.findAndRegisterElements(this);
        return results;

    };
})( jQuery, jQuery.fn.html );

เราเพิ่งตัดการเรียกไปยัง html () เรียกฟังก์ชันการลงทะเบียนด้วยสิ่งนี้ซึ่งในบริบทหมายถึงองค์ประกอบเป้าหมายที่รับเนื้อหาใหม่จากนั้นเราส่งผ่านการเรียกไปยังฟังก์ชัน jquery.html () ดั้งเดิม อย่าลืมส่งคืนผลลัพธ์ของเมธอด html () ต้นฉบับเนื่องจาก JQuery คาดว่าจะเป็นวิธีการผูกมัด

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการแทนที่เมธอดและส่วนขยายให้ดูที่http://www.bennadel.com/blog/2009-Using-Self-Executing-Function-Arguments-To-Override-Core-jQuery-Methods.htmซึ่งเป็นที่ที่ ฉันเปลฟังก์ชั่นปิด นอกจากนี้ตรวจสอบการสอนปลั๊กอินที่เว็บไซต์ของ JQuery


7

นอกเหนือจากเครื่องมือ "ดิบ" ที่จัดทำโดยMutationObserverAPIแล้วยังมีไลบรารี "ความสะดวก" ที่มีอยู่เพื่อทำงานกับการกลายพันธุ์ของ DOM

พิจารณา: MutationObserver แสดงถึงการเปลี่ยนแปลง DOM แต่ละครั้งในแง่ของ subtrees ดังนั้นหากคุณกำลังเช่นการรอคอยสำหรับองค์ประกอบบางอย่างที่จะใส่มันอาจจะเป็นในส่วนลึกของเด็ก mutations.mutation[i].addedNodes[j]

ปัญหาอีกประการหนึ่งคือเมื่อรหัสของคุณเองในการตอบสนองต่อการกลายพันธุ์เปลี่ยน DOM - คุณมักจะต้องการที่จะกรองออก

ห้องสมุดความสะดวกสบายที่ดีที่แก้ไขปัญหาดังกล่าวคือmutation-summary(ข้อจำกัดความรับผิดชอบ: ฉันไม่ใช่ผู้แต่ง แต่เป็นผู้ใช้ที่พึงพอใจ) ซึ่งช่วยให้คุณสามารถระบุข้อความค้นหาที่คุณสนใจและได้รับสิ่งนั้น

ตัวอย่างการใช้งานขั้นพื้นฐานจากเอกสาร:

var observer = new MutationSummary({
  callback: updateWidgets,
  queries: [{
    element: '[data-widget]'
  }]
});

function updateWidgets(summaries) {
  var widgetSummary = summaries[0];
  widgetSummary.added.forEach(buildNewWidget);
  widgetSummary.removed.forEach(cleanupExistingWidget);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.