कैसे जांचें कि गतिशील रूप से संलग्न ईवेंट श्रोता मौजूद है या नहीं?


103

यहाँ मेरी समस्या है: क्या किसी तरह गतिशील रूप से संलग्न ईवेंट श्रोता के अस्तित्व की जांच करना संभव है? या मैं DOM में "onclick" (?) संपत्ति की स्थिति की जांच कैसे कर सकता हूं? मैंने समाधान के लिए स्टैक ओवरफ्लो की तरह ही इंटरनेट खोजा है, लेकिन कोई भाग्य नहीं। यहाँ मेरा html है:

<a id="link1" onclick="linkclick(event)"> link 1 </a>
<a id="link2"> link 2 </a> <!-- without inline onclick handler -->

फिर जावास्क्रिप्ट में मैं गतिशील रूप से बनाई गई ईवेंट श्रोता को 2 लिंक से जोड़ता हूं:

document.getElementById('link2').addEventListener('click', linkclick, false);

कोड अच्छी तरह से चलता है, लेकिन उस संलग्न श्रोता का पता लगाने के मेरे सभी प्रयास विफल हो जाते हैं:

// test for #link2 - dynamically created eventlistener
alert(elem.onclick); // null
alert(elem.hasAttribute('onclick')); // false
alert(elem.click); // function click(){[native code]} // btw, what's this?

jsFiddle यहां है । यदि आप "Add onclick for 2" और फिर "[लिंक 2]" पर क्लिक करते हैं, तो घटना अच्छी तरह से समाप्त हो जाती है, लेकिन "टेस्ट लिंक 2" हमेशा गलत रिपोर्ट करता है। क्या कोई मदद कर सकता है?


1
मुझे यह कहने के लिए खेद है, लेकिन आपके वर्तमान तरीके का उपयोग करके इवेंट बाइंडिंग प्राप्त करना असंभव है: stackoverflow.com/questions/5296858/…
इवान

1
आप इसे क्रोम देव टूल का उपयोग कर सकते हैं: stackoverflow.com/a/41137585/863115
arufian

आप इसे अपने स्वयं के भंडारण को बनाकर कर सकते हैं जो श्रोताओं का ध्यान रखता है। अधिक के लिए मेरा जवाब देखें ।
एंजेल पोलिटिस

यदि उद्देश्य एक घटना को रोकना है जो पहले से ही फिर से जोड़ा जा रहा है तो सही उत्तर यहां है । मूल रूप से, यदि आप एक अनाम के बजाय एक नामित फ़ंक्शन का उपयोग करते हैं, तो डुप्लिकेट समान इवेंट श्रोताओं को छोड़ दिया जाएगा और आपको उनके बारे में चिंता करने की आवश्यकता नहीं है।
सायनकेप्स

यदि आप डुप्लिकेट श्रोताओं के बारे में चिंतित हैं तो फिर से जोड़ने से पहले वर्तमान ईवेंट श्रोता को हटा दें। यह सही नहीं है, लेकिन यह सरल है।
१२:२१ पर जैक्सनक्रा

जवाबों:


49

यह जांचने का कोई तरीका नहीं है कि गतिशील रूप से संलग्न ईवेंट श्रोता मौजूद हैं या नहीं।

केवल एक तरह से आप देख सकते हैं कि कोई ईवेंट श्रोता संलग्न है या नहीं, इस तरह से ईवेंट श्रोताओं को संलग्न करना है:

elem.onclick = function () { console.log (1) }

आप तब परीक्षण कर सकते हैं यदि कोई ईवेंट श्रोता onclickरिटर्निंग !!elem.onclick(या कुछ इसी तरह) से जुड़ा था ।


33

मैंने ऐसा कुछ किया:

const element = document.getElementById('div');

if (element.getAttribute('listener') !== 'true') {
     element.addEventListener('click', function (e) {
         const elementClicked = e.target;
         elementClicked.setAttribute('listener', 'true');
         console.log('event has been attached');
    });
}

एक तत्व के लिए विशेष विशेषता बनाना जब श्रोता संलग्न होता है और फिर जाँचता है कि क्या यह मौजूद है।


4
यह वह तरीका है जो मैंने अतीत में इस्तेमाल किया है। मेरी सिफारिश एक बहुत ही विशिष्ट वाक्य रचना संरचना का उपयोग करने के लिए होगी। IE "श्रोता" के बजाय, घटना का उपयोग करें। तो "डेटा-इवेंट-क्लिक"। यह उस घटना में कुछ लचीलापन प्रदान करता है जिसे आप एक से अधिक घटनाओं के लिए देख रहे हैं, और चीजों को थोड़ा अधिक पठनीय रखता है।
conrad10781

@ Conrad10781 के जोड़ के साथ यह सबसे विश्वसनीय और सरल तरीका लगता है। यदि किसी भी कारण से तत्व रेंडर किया जाता है और ईवेंट श्रोता डिस्कनेक्ट हो जाता है, तो यह विशेषता रीसेट भी हो जाएगी।
A:

23

मैं आपके फ़ंक्शन के बाहर एक बूलियन बनाऊंगा जो FALSE के रूप में शुरू होता है और जब आप ईवेंट संलग्न करते हैं तो TRUE पर सेट हो जाता है। इससे पहले कि आप इस घटना को फिर से संलग्न करने से पहले आपके लिए किसी प्रकार के ध्वज के रूप में काम करेंगे। यहाँ विचार का एक उदाहरण है।

// initial load
var attached = false;

// this will only execute code once
doSomething = function()
{
 if (!attached)
 {
  attached = true;
  //code
 }
} 

//attach your function with change event
window.onload = function()
{
 var txtbox = document.getElementById('textboxID');

 if (window.addEventListener)
 {
  txtbox.addEventListener('change', doSomething, false);
 }
 else if(window.attachEvent)
 {
  txtbox.attachEvent('onchange', doSomething);
 }
}

इसके लिए आपको अटैच किए गए ईवेंट के कोड को बदलने की आवश्यकता होती है ताकि यह अटैच किया जा सके ( इस या इस उत्तर के समान )। यदि आप कोड को नियंत्रित नहीं करते हैं तो यह काम नहीं करेगा।
user202729

7

संभव डुप्लिकेट: जांचें कि क्या किसी तत्व के पास उस पर ईवेंट श्रोता है। कोई jQuery नहीं, कृपया मेरा जवाब खोजें।

मूल रूप से यहाँ क्रोमियम (क्रोम) ब्राउज़र के लिए चाल है:

getEventListeners(document.querySelector('your-element-selector'));

1
दरअसल, यहां: stackoverflow.com/a/41137585/1431728
जॉनके

6

tl; dr : नहीं, आप किसी भी मूल समर्थित तरीके से ऐसा नहीं कर सकते।


मुझे इसे प्राप्त करने का एकमात्र तरीका एक कस्टम स्टोरेज ऑब्जेक्ट बनाना होगा जहां आप श्रोताओं को जोड़े रखने का रिकॉर्ड रखेंगे। निम्नलिखित पंक्तियों के साथ कुछ:

/* Create a storage object. */
var CustomEventStorage = [];

चरण 1: सबसे पहले, आपको एक फ़ंक्शन की आवश्यकता होगी जो स्टोरेज ऑब्जेक्ट को पीछे कर सकता है और तत्व (या गलत) दिए गए तत्व के रिकॉर्ड को वापस कर सकता है।

/* The function that finds a record in the storage by a given element. */
function findRecordByElement (element) {
    /* Iterate over every entry in the storage object. */
    for (var index = 0, length = CustomEventStorage.length; index < length; index++) {
        /* Cache the record. */
        var record = CustomEventStorage[index];

        /* Check whether the given element exists. */
        if (element == record.element) {
            /* Return the record. */
            return record;
        }
    }

    /* Return false by default. */
    return false;
}

चरण 2: फिर, आपको एक फ़ंक्शन की आवश्यकता होगी जो एक इवेंट श्रोता को जोड़ सकता है लेकिन श्रोता को स्टोरेज ऑब्जेक्ट में भी डाल सकता है।

/* The function that adds an event listener, while storing it in the storage object. */
function insertListener (element, event, listener, options) {
    /* Use the element given to retrieve the record. */
    var record = findRecordByElement(element);

    /* Check whether any record was found. */
    if (record) {
        /* Normalise the event of the listeners object, in case it doesn't exist. */
        record.listeners[event] = record.listeners[event] || [];
    }
    else {
        /* Create an object to insert into the storage object. */
        record = {
            element: element,
            listeners: {}
        };

        /* Create an array for event in the record. */
        record.listeners[event] = [];

        /* Insert the record in the storage. */
        CustomEventStorage.push(record);
    }

    /* Insert the listener to the event array. */
    record.listeners[event].push(listener);

    /* Add the event listener to the element. */
    element.addEventListener(event, listener, options);
}

चरण 3: आपके प्रश्न की वास्तविक आवश्यकता के संबंध में, आपको यह जाँचने के लिए निम्न फ़ंक्शन की आवश्यकता होगी कि क्या किसी तत्व को किसी निर्दिष्ट ईवेंट के लिए इवेंट श्रोता जोड़ा गया है।

/* The function that checks whether an event listener is set for a given event. */
function listenerExists (element, event, listener) {
    /* Use the element given to retrieve the record. */
    var record = findRecordByElement(element);

    /* Check whether a record was found & if an event array exists for the given event. */
    if (record && event in record.listeners) {
        /* Return whether the given listener exists. */
        return !!~record.listeners[event].indexOf(listener);
    }

    /* Return false by default. */
    return false;
}

चरण 4: अंत में, आपको एक फ़ंक्शन की आवश्यकता होगी जो एक श्रोता को स्टोरेज ऑब्जेक्ट से हटा सकता है।

/* The function that removes a listener from a given element & its storage record. */
function removeListener (element, event, listener, options) {
    /* Use the element given to retrieve the record. */
    var record = findRecordByElement(element);

    /* Check whether any record was found and, if found, whether the event exists. */
    if (record && event in record.listeners) {
        /* Cache the index of the listener inside the event array. */
        var index = record.listeners[event].indexOf(listener);

        /* Check whether listener is not -1. */
        if (~index) {
            /* Delete the listener from the event array. */
            record.listeners[event].splice(index, 1);
        }

        /* Check whether the event array is empty or not. */
        if (!record.listeners[event].length) {
            /* Delete the event array. */
            delete record.listeners[event];
        }
    }

    /* Add the event listener to the element. */
    element.removeEventListener(event, listener, options);
}

स्निपेट:


हालाँकि ओपी ने सवाल पोस्ट किए हुए 5 साल से अधिक समय बीत चुका है, मेरा मानना ​​है कि भविष्य में इस पर ठोकर खाने वाले लोगों को इस जवाब से फायदा होगा, इसलिए बेझिझक सुझाव दें या इसमें सुधार करें। 😊


इस समाधान के लिए धन्यवाद, यह सीधा और मजबूत है। एक टिप्पणी हालांकि, एक छोटी सी गलती है। फ़ंक्शन "removeListener" जाँचता है कि क्या इवेंट सरणी खाली है या नहीं, लेकिन टर्नरी गलत है। इसे "if (record.listeners [इवेंट] .length! = - 1)" कहना चाहिए।
जेपीए

5

उदाहरण के लिए Chrome इंस्पेक्टर का उपयोग करके यदि आपका EventListener मौजूद है, तो आप हमेशा स्वयं जाँच कर सकते हैं। तत्व टैब में आपके पास पारंपरिक "शैलियाँ" उपटैब है और इसके करीब एक और है: "इवेंट श्रोता"। जो आपको उनके लिंक्ड तत्वों के साथ सभी EventListeners की सूची देगा।


5

यह अजीब लगता है कि यह विधि मौजूद नहीं है। क्या इसे अंत में जोड़ने का समय है?

यदि आप चाहते हैं कि आप निम्नलिखित कुछ पसंद कर सकें:

var _addEventListener = EventTarget.prototype.addEventListener;
var _removeEventListener = EventTarget.prototype.removeEventListener;
EventTarget.prototype.events = {};
EventTarget.prototype.addEventListener = function(name, listener, etc) {
  var events = EventTarget.prototype.events;
  if (events[name] == null) {
    events[name] = [];
  }

  if (events[name].indexOf(listener) == -1) {
    events[name].push(listener);
  }

  _addEventListener(name, listener);
};
EventTarget.prototype.removeEventListener = function(name, listener) {
  var events = EventTarget.prototype.events;

  if (events[name] != null && events[name].indexOf(listener) != -1) {
    events[name].splice(events[name].indexOf(listener), 1);
  }

  _removeEventListener(name, listener);
};
EventTarget.prototype.hasEventListener = function(name) {
  var events = EventTarget.prototype.events;
  if (events[name] == null) {
    return false;
  }

  return events[name].length;
};

3

यहाँ एक स्क्रिप्ट है जिसका उपयोग मैंने गतिशील रूप से संलग्न ईवेंट श्रोता के अस्तित्व की जाँच के लिए किया था। मैंने किसी ईवेंट हैंडलर को एक तत्व में संलग्न करने के लिए jQuery का उपयोग किया, फिर उस ईवेंट को ट्रिगर करें (इस मामले में 'क्लिक' ईवेंट)। इस तरह मैं घटना के गुणों को पुनः प्राप्त कर सकता हूं और कब्जा कर सकता हूं जो केवल तभी मौजूद होंगे जब इवेंट हैंडलर संलग्न है।

var eventHandlerType;

$('#contentDiv').on('click', clickEventHandler).triggerHandler('click');

function clickEventHandler(e) {
    eventHandlerType = e.type;
}

if (eventHandlerType === 'click') {
    console.log('EventHandler "click" has been applied');
}

2
आप अपने तत्व को मूल रूप से उस तत्व को चिह्नित करने के लिए एक संपत्ति निर्दिष्ट कर सकते हैं जो उसके साथ जुड़ी एक घटना है;
जस्टिन

2

एक क्रॉस ब्राउज़र फ़ंक्शन प्रतीत नहीं होता है जो किसी दिए गए तत्व के तहत पंजीकृत घटनाओं की खोज करता है।

हालांकि, कुछ ब्राउज़रों में उनके विकास टूल का उपयोग करने वाले तत्वों के लिए कॉल बैक फ़ंक्शन देखना संभव है। यह निर्धारित करने के लिए उपयोगी हो सकता है कि वेब पेज कैसे काम करता है या कोड डीबगिंग के लिए निर्धारित होता है।

फ़ायरफ़ॉक्स

सबसे पहले, डेवलपर टूल के भीतर इंस्पेक्टर टैब में तत्व देखें । यह संभव है:

  • पेज पर वेब पेज है कि आप मेनू से निरीक्षण किया और चयन करने के लिए "तत्व का निरीक्षण" चाहते हैं पर आइटम पर राइट क्लिक करके।
  • तत्व का चयन करने के लिए एक फ़ंक्शन का उपयोग करके कंसोल के भीतर , जैसे कि document.querySelector , और फिर इंस्पेक्टर टैब में इसे देखने के लिए तत्व के पास आइकन पर क्लिक करना ।

यदि कोई ईवेंट तत्व में पंजीकृत किया गया था, तो आपको एक बटन दिखाई देगा, जिसमें ईवेंट शब्द होगा तत्व के बगल में । इसे क्लिक करने से आप उन घटनाओं को देख पाएंगे जो तत्व के साथ पंजीकृत हैं। किसी ईवेंट के पास तीर पर क्लिक करने से आप इसके लिए कॉलबैक फ़ंक्शन देख सकते हैं।

क्रोम

सबसे पहले, डेवलपर टूल के भीतर एलिमेंट्स टैब में तत्व देखें। यह संभव है:

  • पृष्ठ पर वेब पेज है कि आप मेनू से निरीक्षण करने के लिए और चयन "का निरीक्षण" चाहते हैं पर आइटम पर राइट क्लिक करके
  • तत्व का चयन करने के लिए एक फ़ंक्शन का उपयोग करके कंसोल के भीतर , जैसे कि document.querySelector , तत्व पर राइट क्लिक करना, और इंस्पेक्टर टैब में इसे देखने के लिए "Reveal in Elements पैनल" का चयन करना ।

वेब पेज तत्वों वाले पेड़ को दिखाने वाली खिड़की के अनुभाग के पास, "इवेंट श्रोताओं" नामक एक टैब के साथ एक और अनुभाग होना चाहिए। इसे उन घटनाओं को देखने के लिए चुनें जो तत्व में पंजीकृत थे। किसी दिए गए ईवेंट के लिए कोड देखने के लिए, उसके दाईं ओर दिए गए लिंक पर क्लिक करें।

Chrome में, तत्व के लिए ईवेंट्स को getEventListeners फ़ंक्शन का उपयोग करके भी पाया जा सकता है । हालाँकि, मेरे परीक्षणों के आधार पर, GetEventListeners फ़ंक्शन उन घटनाओं को सूचीबद्ध नहीं करता है जब कई तत्व इसे पास करते हैं। यदि आप पृष्ठ के उन सभी तत्वों को खोजना चाहते हैं जिनमें श्रोता हैं और उन श्रोताओं के लिए कॉलबैक फ़ंक्शन देखते हैं, तो आप ऐसा करने के लिए कंसोल में निम्न कोड का उपयोग कर सकते हैं:

var elems = document.querySelectorAll('*');

for (var i=0; i <= elems.length; i++) {
    var listeners = getEventListeners(elems[i]);

    if (Object.keys(listeners).length < 1) {
        continue;
    }

    console.log(elems[i]);

    for (var j in listeners) {
        console.log('Event: '+j);

        for (var k=0; k < listeners[j].length; k++) {
            console.log(listeners[j][k].listener);
        }
    }
}

यदि आप दिए गए ब्राउज़रों या अन्य ब्राउज़रों में ऐसा करने के तरीकों के बारे में जानते हैं तो कृपया इस उत्तर को संपादित करें।


1

मुझे यह देखने की कोशिश करने से पता चला कि क्या मेरा कार्यक्रम संलग्न था ...।

यदि तुम करो :

item.onclick

यह "अशक्त" वापस आ जाएगा

लेकिन अगर तुम करते हो:

item.hasOwnProperty('onclick')

तो यह "सही" है

इसलिए मुझे लगता है कि जब आप इवेंट हैंडलर जोड़ने के लिए "addEventListener" का उपयोग करते हैं, तो इसे एक्सेस करने का एकमात्र तरीका "hasOwnProperty" है। काश मैं जानता था कि क्यों या कैसे लेकिन अफसोस, शोध के बाद, मुझे स्पष्टीकरण नहीं मिला।


2
onclickसे अलग है .addEventListener- यह एक विशेषता को प्रभावित करता है जबकि .addEventListenerनहीं
Zach Saucier

1

अगर मैं अच्छी तरह से समझता हूं कि आप केवल यह देख सकते हैं कि एक श्रोता की जाँच की गई है, लेकिन कौन सा श्रोता विशेष रूप से प्रस्तुतकर्ता नहीं है।

तो कुछ तदर्थ कोड आपके कोडिंग प्रवाह को संभालने के लिए अंतर को भर देंगे। एक व्यवहारिक विधि एक stateप्रयोग चर बनाने के लिए होगी । उदाहरण के लिए, निम्नलिखित के रूप में एक श्रोता के चेकर संलग्न करें:

var listenerPresent=false

फिर यदि आप एक श्रोता सेट करते हैं तो बस मूल्य बदलें:

listenerPresent=true

तब अपने ईवेंटसिस्टनर के कॉलबैक के अंदर आप विशिष्ट कार्यप्रणालियों को निर्दिष्ट कर सकते हैं और इसी तरह, उदाहरण के लिए चर के रूप में कुछ राज्य के आधार पर कार्यात्मकताओं तक पहुंच वितरित करते हैं:

accessFirstFunctionality=false
accessSecondFunctionality=true
accessThirdFunctionality=true

1

इसे जोड़ने से पहले घटना को हटा दें:

document.getElementById('link2').removeEventListener('click', linkclick, false);
document.getElementById('link2').addEventListener('click', linkclick, false);

यह एक अच्छी चाल है, लेकिन मुझे लगता है कि यह केवल तभी काम करता है जब आपके पास उस फ़ंक्शन के लिए रेफरी हो जो वर्तमान में "जोड़ा" इवेंट-श्रोताओं में से एक है। मुझे लगता है कि यह स्पष्ट रूप से मानक एपीआई की कमी है, अगर हम किसी भी घटना-श्रोता को जोड़ सकते हैं, तो यह भी जांचना संभव है कि घटना-श्रोताओं को अब तक क्या जोड़ा गया है। यह लगभग घटना-श्रोताओं की तरह है वर्तमान में "केवल चर लिखें" जो एक अस्पष्ट अवधारणा की तरह लगता है।
पानू तर्क

0

मैंने अभी एक स्क्रिप्ट लिखी है जो आपको इसे हासिल करने की अनुमति देती है। यह आपको दो वैश्विक कार्य देता है: hasEvent(Node elm, String event)और getEvents(Node elm)जिसका आप उपयोग कर सकते हैं। ज्ञात हो कि यह EventTargetप्रोटोटाइप विधि को संशोधित करता है add/RemoveEventListener, और HTML मार्कअप या जावास्क्रिप्ट सिंटैक्स के माध्यम से जोड़ी गई घटनाओं के लिए काम नहीं करता हैelm.on_event = ...

GitHub पर अधिक जानकारी

लाइव डेमो

स्क्रिप्ट:

var hasEvent,getEvents;!function(){function b(a,b,c){c?a.dataset.events+=","+b:a.dataset.events=a.dataset.events.replace(new RegExp(b),"")}function c(a,c){var d=EventTarget.prototype[a+"EventListener"];return function(a,e,f,g,h){this.dataset.events||(this.dataset.events="");var i=hasEvent(this,a);return c&&i||!c&&!i?(h&&h(),!1):(d.call(this,a,e,f),b(this,a,c),g&&g(),!0)}}hasEvent=function(a,b){var c=a.dataset.events;return c?new RegExp(b).test(c):!1},getEvents=function(a){return a.dataset.events.replace(/(^,+)|(,+$)/g,"").split(",").filter(function(a){return""!==a})},EventTarget.prototype.addEventListener=c("add",!0),EventTarget.prototype.removeEventListener=c("remove",!1)}();

-1

आप सिद्धांत रूप में piggyback addEventListener और removeEventListener को 'इस' ऑब्जेक्ट में एक ध्वज हटाने के लिए जोड़ सकते हैं। बदसूरत और मैंने परीक्षण नहीं किया है ...

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.