Home > Back-end >  best way to incorporate vanilla event listeners on multiple components
best way to incorporate vanilla event listeners on multiple components

Time:11-17

I have 2 event listeners defined in the mounted lifecycle of a component, that allow a user to close out of a v-dialog by either double clicking outside or pressing escape. Writing these vanilla event listeners was the only way I knew to achieve the functionality that I wanted. Something like this:

<template>
  <v-container>
    <v-dialog :value="value" max-width="55vw" height="70vw" persistent>
      ...some stuff...
    </v-dialog>
  </v-container>
</template>

<script>
export default {
  name: "a name",
  props: {
    value: { required: true },
  },
  mounted() {
    let that = this;
    document.addEventListener("keyup", function (evt) {
      if (evt.key === "Escape") {
        that.closeDialog();
      }
    });
    document.addEventListener("dblclick", function (e) {
      if (e.target == document.getElementsByClassName("v-overlay__scrim")[0]) {
        that.closeDialog();
      }
    });
  },
  unmounted() {
    window.removeEventListener("keyup");
    window.removeEventListener("dblclick");
  },
  methods: {
    closeDialog() {
      this.$emit("input");
    },
  },
};
</script>

I would like to extend this functionality of closing out of v-dialogs to several other components, but adding these event listeners to multiple components' mounted block seems redundant. Is there a better way to achieve this?

CodePudding user response:

In my opinion, you shouldn't use native events for this case. Also adding an event listener over the document on an specific Vue component, could lead to confusions, since you're always listening to that event everywhere (in your case, "esc" key being pushed). Imagine if you have a large number of components and when you push "esc", some code is being executed. If you're not the author of this piece of code, it's "hard" to tell from where it comes.

For this case I would recommend: using a Mixin that could contain the lifecycle hooks (vue 2) or using a composable for importing the function (vue 2 with vue/composition-api or vue 3) and manually registering it with the proper lifecycle hook function.

BTW, on your code, on the remove event listener part, you should pass the function reference. So it would be better to extract the method to a proper vue method of that component.

mounted() {
    let that = this;
    document.addEventListener("keyup", this.close);
    document.addEventListener("dblclick", this.close2);
  },
  unmounted() {
    window.removeEventListener("keyup", this.close);
    window.removeEventListener("dblclick", this.close2);
  },
  methods: {
    close(evt) {
      if (evt.key === "Escape") {
        this.$emit("input");
      }
    },
    close2(e) {
      if (e.target == document.getElementsByClassName("v-overlay__scrim")[0]) {
        this.$emit("input");
      }
    },

  },
  • Related