简体   繁体   中英

Capture all click events inside Vue application

I need to capture all click events triggered by the user inside my Vue.js application. My first step was to add an onclick listener to the #app div:

<div id="app" @click="onClickApp"></div>
// ...
<script>
  export default {
    methods: {
      onClickApp() {
        // increment counter in vuex store
      }
   }
</script>

This captures all click events happening directly inside the App component. The issue is that I'm using a Bootstrap Modal (provided via BootstrapVue) and I need to capture the clicks inside it as well. This is not working at the moment, even if I set another @click listener on the <b-modal></b-modal> component (syntax for vue-cli).

This is what I also tried (in main.js ):

new Vue({
  router,
  store,
  render: h => h(App),
  mounted: function() {
    this.$el.addEventListener('click', this.onClickVue)
  },
  beforeDestroy: function () {
    this.$el.removeEventListener('click', this.onClickVue)
  },
  methods: {
    onClickVue: function (e) {
      this.$store.commit(mutationTypes.INCREMENT_CLICKS)
    }
  });

Same problem, clicks inside the Bootstrap Modals are not firing a click event.

I could only get this to work by using the mouseup event..

CodePen mirror: https://codepen.io/oze4/pen/PgKWRW?editors=1010

 new Vue({ el: "#app", data: { modalShow: false }, mounted() { document.addEventListener("mouseup", e => { let m = `x: ${e.clientX} | y: ${e.clientY}`; console.log(m); }) } });
 <script src="https://unpkg.com/vue@2.5.17/dist/vue.min.js"></script> <script src="https://unpkg.com/bootstrap-vue@2.0.0-rc.11/dist/bootstrap-vue.min.js"></script> <link href="https://unpkg.com/bootstrap@4.1.3/dist/css/bootstrap.min.css" rel="stylesheet" /> <link href="https://unpkg.com/bootstrap-vue@2.0.0-rc.11/dist/bootstrap-vue.css" rel="stylesheet" /> <div id="app"> <div style="margin: 5px 0px 0px 40px"> <b-button @click="modalShow = !modalShow">Open Modal</b-button> <b-modal v-model="modalShow">Hello From Modal!</b-modal> </div> </div>

A better answer is just adding ev to onClickApp, so do onClickApp(ev) inside your methods.

Now, you have access to the click event.

This should work ;-)

- <div id="app" @click="onClickApp"></div>
+ <div id="app"></div>
// ...
<script>
  export default {
    methods: {
      onClickApp() {
        // increment counter in vuex store
      }
   },
+  mounted() {
+    window.document.addEventListener('click'), this.onClickApp)
+  },
+  beforeDestroy() {
+    window.document.removeEventListener('click'), this.onClickApp)
+  }
</script>

I couldn't find a way to test with Bootstrap Vue, but this might do.

TLDR: Create a plugin which will run whenever any of your components are instantiated. Put a listener on the root element.

https://codesandbox.io/s/kxwz85pl65

const MyPlugin = {
  install(Vue, options) {
    Vue.mixin({
      mounted() {
        setTimeout(() => {
          let cb = this.$root.$el.onclick;
          this.$root.$el.onclick = (e) => {
            alert("element clicked");
            if (cb) {
              cb(e);
            }
          };
        }, 10);
      }
    });
  }
};

EDIT:

As of writing this Vue Bootstrap doesn't seem to allow click events for the modal itself, though elements inside of it can be clicked.

https://codesandbox.io/embed/kxwz85pl65

EDIT again, you can use set timeout if you really want to. It's a bit of a hack though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM