Adding an event listener to an element that doesn't exist yet in vanilla javascript

前端 未结 4 2335
我在风中等你
我在风中等你 2021-02-18 16:23

In JQuery I can do:

$(document).on(\"click\",\"a.someBtn\",function(e){
    console.log(\"hi\");
});

to add an event listener to an element th

相关标签:
4条回答
  • 2021-02-18 16:41

    What you want is to use DOM MutationObserver Events to apply the addEventListener. This DOM API is available on all major browser since 2012 I think.

    I use this on to lower the google translator bar created by their snippet (https://www.w3schools.com/howto/howto_google_translate.asp). Since it creates the element dynamically (an iframe), it is the same problem you have. Just change the callback function and variables for your need.

    //Observer for Google translator bar creation and action to move to bottom
    // Select the nodetree that will be observed for mutations
    var nodetree = document.getElementsByTagName("body")[0];
    // Select the target node atributes (CSS selector)
    var targetNode = "iframe.goog-te-banner-frame";
    // Options for the observer (which mutations to observe)
    var config = { attributes: false, childList: true };
    // Callback function to execute when mutations of DOM tree are observed
    var lowerGoogleTranslateBar = function(mutations_on_DOMtree) {
        for(var mutation of mutations_on_DOMtree) {
            if (mutation.type == 'childList') {
                console.log(mutation);
                if (document.querySelector(targetNode) != null) {
                    //40px is the height of the bar
                    document.querySelector(targetNode).style.setProperty("top", "calc(100% - 40px)");
                    //after action is done, disconnect the observer from the nodetree
                    observerGoogleTranslator.disconnect();
                }
            }
        }
    };
    // Create an observer instance linked to the callback function
    var observerGoogleTranslator = new MutationObserver(lowerGoogleTranslateBar);
    // Start observing the target node for configured mutations
    observerGoogleTranslator.observe(nodetree, config);
    

    You can learn more about this here: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

    0 讨论(0)
  • 2021-02-18 16:49

    Here's a function that will let you add "live" events like jQuery's .on. It can be invoked like this:

    addLiveListener(scope, selector, event, function reference);
    

    Take a look at the function comment for the description of each of those parameters.

    /**
     * Adds a istener for specific tags for elements that may not yet
     * exist.
     * @param scope a reference to an element to look for elements in (i.e. document)
     * @param selector the selector in form [tag].[class] (i.e. a.someBtn)
     * @param event and event (i.e. click)
     * @param funct a function reference to execute on an event
     */
    function addLiveListener(scope, selector, event, funct) {
      /**
       * Set up interval to check for new items that do not 
       * have listeners yet. This will execute every 1/10 second and
       * apply listeners to 
       */
      setInterval(function() {
        var selectorParts = selector.split('.');
        var tag = selectorParts.shift();
        var className;
        if (selectorParts.length)
          className = selectorParts.shift();
    
        if (tag != "") {
          tag = tag.toUpperCase();
          var elements = scope.getElementsByTagName(tag);
        } else
          var elements = scope.getElementsByClassName(className);
    
        for (var i = 0; i < elements.length; i++) {
          if (elements[i][event + '_processed'] === undefined && (tag == "" || elements[i].tagName == tag)) {
            elements[i].addEventListener(event, funct);
          }
        }
      }, 1000);
    }
    

    And here's a full working demo:

    /**
     * Adds another anchor with no events attached and lets 
     * our other code auto-attach events
     */
    var currentAnchor = 3;
    
    function addAnchor() {
      currentAnchor++;
      var element = document.createElement('a');
      element.href = "#";
      element.innerHTML = "Anchor " + currentAnchor;
      element.className = "someBtn";
      document.getElementById("holder").appendChild(element);
    }
    
    /**
     * Adds a istener for specific tags for elements that may not yet
     * exist.
     * @param scope a reference to an element to look for elements in (i.e. document)
     * @param selector the selector in form [tag].[class] (i.e. a.someBtn)
     * @param event and event (i.e. click)
     * @param funct a function reference to execute on an event
     */
    function addLiveListener(scope, selector, event, funct) {
      /**
       * Set up interval to check for new items that do not 
       * have listeners yet. This will execute every 1/10 second and
       * apply listeners to 
       */
      setInterval(function() {
        var selectorParts = selector.split('.');
        var tag = selectorParts.shift();
        var className;
        if (selectorParts.length)
          className = selectorParts.shift();
    
        if (tag != "") {
          tag = tag.toUpperCase();
          var elements = scope.getElementsByTagName(tag);
        } else
          var elements = scope.getElementsByClassName(className);
    
        for (var i = 0; i < elements.length; i++) {
          if (elements[i][event + '_processed'] === undefined && (tag == "" || elements[i].tagName == tag)) {
            elements[i].addEventListener(event, funct);
          }
        }
      }, 1000);
    }
    
    /**
     * Now let's add live listener for "a" tags
     */
    addLiveListener(document, "a.someBtn", "click", function() {
      alert('Clicked ' + this.innerHTML);
    });
    a {
      margin-right: 10px;
    }
    <!-- Add some pre-existing anchors -->
    <p id="holder">
      <a href="#" class="someBtn">Anchor 1</a><a href="#" class="someBtn">Anchor 2</a><a href="#" class="someBtn">Anchor 3</a>
    </p>
    
    <!-- A button to add dynamic new anchors -->
    <input type="button" value="Add anchor" onclick="addAnchor();" />

    0 讨论(0)
  • 2021-02-18 17:05

    Use the target property in the event object to get the clicked element. Then, manually test for type/attributes/ids

    document.addEventListener( "click", someListener );
    
    function someListener(event){
        var element = event.target;
        if(element.tagName == 'A' && element.classList.contains("someBtn")){
            console.log("hi");
        }
    }
    
    0 讨论(0)
  • 2021-02-18 17:06

    You can use event.target

    A reference to the object that dispatched the event.

    Code

    (function () {
        "use strict";
            document.getElementsByTagName('body')[0].addEventListener('click', function(e) {
            if (e.target.tagName == 'A' && e.target.classList.contains("someBtn")) {
              alert('Clicked');
            }
          }, false);
    })();
    

    (function() {
      "use strict";
      var a = document.createElement('a');
      a.textContent = 'Click Me';
      a.href = '#';
      document.body.appendChild(a);
    
      document.getElementsByTagName('body')[0].addEventListener('click', function(e) {
        if (e.target.tagName == 'A') {
          alert('Clicked');
        }
      }, false);
    })();

    0 讨论(0)
提交回复
热议问题