Polymer: Detect click outside of custom element

2019-09-06 00:27发布

问题:

I have a custom element and would like to detect clicks outside of it. For example

<dom-module id="simple-element">



<style>
  </style>

  <template>
    <content></content>
  </template>

</dom-module>

<script>
  (function() {
    Polymer({
      is: 'simple-element',
      listeners: {
        'tap': 'regularTap'
      },
      regularTap: function() {
        console.log("i was tapped");
      }
    });
  })();
</script>

Is there an event where I can listen to which will tell me when user has clicked outside of the element? Thanks.

回答1:

Something along these lines should do what you want:

window.addEventListener('click', (e) => {
  var target = event.target;

  while(target != this && target != document.body) {
    target = Polymer.dom(target).node.domHost.parentNode;
    // might need some additional steps to get the parent from inside custom elements
    // don't know by heart
  }
  if(target == this) {
    // inside element
  } else {
    // outside element
  }
});


回答2:

Modified the code so that it actually works:

var that = this;

window.addEventListener("click", function(e){
    var target = e.target;

    while (target != that && target != document.body) {
        target = Polymer.dom(target).node.parentElement;
    }

    if (target == that) {
         console.log("inside element");
    } else {
         console.log("outside element");
    }
});


回答3:

You can use a behavior like this:

    <script>
      /** @polymerBehavior Polymer.HarleyClickOutsideBehavior */
      Polymer.HarleyClickOutsideBehavior = {

        ready: function () {
          // bind listener method
          this.clickOutsideListenerBinded = this._clickOutsideListener.bind(this)
        },

        detached: function () {
          this._clickOutsideUnlisten()
        },

        clickOutsideListen: function () {
          // run this method to start listening
          this._clickOutsideUnlisten()
          window.addEventListener('click', this.clickOutsideListenerBinded, false)
        },

        _clickOutsideUnlisten: function () {
          window.removeEventListener('click', this.clickOutsideListenerBinded, false)
        },

        _clickOutsideListener: function (ev) {
          // check if the user has clicked on my component or on my children
          var isOutside = !ev.path.find(function (path) {
            return path === this
          }.bind(this))
          if (isOutside) {
            this.onClickOutside()
            this._clickOutsideUnlisten()
          }
        },

        onClickOutside: function () {
          // overwrite this method to be notified
        }

      }
    </script>


回答4:

I've found a simpler solution haven't tested it on all browsers yet, but makes sense. So I add a global listener to window, and a listener to the custom element. This way click inside will call both, click outside will only call global..

listenToClickOutside() {
            this.addEventListener("click", thisClick, false);
            window.addEventListener("click", windowClick, false);

            var clicksInside = 0;
            var thisRef = this;

            function thisClick() {
                clicksInside++
            }

            function windowClick(event) {
                clicksInside--;
                if (clicksInside < 0) {
                    thisRef.removeEventListener("click", thisClick, false);
                    window.removeEventListener("click", windowClick, false);
                    // CLICKED outside
                }
            }
        }