简体   繁体   中英

how to hide dropdown menu if we click outside the menu in vuejs

I am using a dropdown menu components in vuejs to make normal dropdown menu. My code is for dropdown component is :

<template>
    <span class="dropdown" :class="{shown: state}">
        <a href="#" @click.prevent="toggleDropdown" class="dropdown-toggle">toggle menu</a>
            <div class="dropdown-menu" v-show="state">
                <ul class="list-unstyled">
                    <slot></slot>
                </ul>
            </div>
        </transition>
    </span>
</template>

<script>
export default {
    name: 'dropdown',
    data () {
        return {
            state: false
        }
    },
    methods: {
        toggleDropdown (e) {
            this.state = !this.state;
        }
    }
}
</script>

Now I am importing the dropdown component in my VUE app at various place by using following code in the template

<dropdown>
    <li>
         Action
    </li>
</dropdown>

Now that is working fine but I want that only one dropdown should be active at the same time.

I have done little research and found that i can use plugins like https://github.com/davidnotplay/vue-my-dropdown but I don't want to use that. Again i have also studied how the above example works but I want to implement this dropdown functionality in such a way that my dropdown component would take care of all event related to dropdown. So can you help me how to achieve that?

Have a look at vue-clickaway.( Link )

Sometimes you need to detect clicks outside of the element (to close a modal window or hide a dropdown select). There is no native event for that, and Vue.js does not cover you either. This is why vue-clickaway exists. Please check out the demo before reading further.

I know it's quite an old question but I think the best way to do that without any external plugins is to add a click listener to mounted lifecycle hook (and remove it on beforeDestroy hook) and filter the clicks on your component so it only hides when clicked outside.

<template>
    <span class="dropdown" :class="{shown: state}">
      <a href="#" @click.prevent="toggleDropdown" class="dropdown-toggle">toggle menu</a>
            <div class="dropdown-menu" v-show="state">
                <ul class="list-unstyled">
                    <slot></slot>
                </ul>
            </div>
        <transition/>
    </span>
</template>

<script>
export default {
  name: 'dropdown',
  data () {
    return {
      state: false
    }
  },
  methods: {
    toggleDropdown (e) {
      this.state = !this.state
    },
    close (e) {
      if (!this.$el.contains(e.target)) {
        this.state = false
      }
    }
  },
  mounted () {
    document.addEventListener('click', this.close)
  },
  beforeDestroy () {
    document.removeEventListener('click',this.close)
  }
}
</script>

In Vue 3 the following should work

Note that the @click.stop on the dropdown trigger and on the dropdown content prevents the document event from executing the close function.

<template>
  <div class="dropdown" :class="{'is-active': dropdown.active.value}">
    <div class="dropdown-trigger">
      <button class="button" @click.stop="dropdown.active.value = !dropdown.active.value">
        Toggle
      </button>
    </div>
    <div class="dropdown-menu" role="filter">
      <div class="dropdown-content" @click.stop>
        <!-- dropdown items -->
      </div>
    </div>
  </div>
</template>

<script>

import { defineComponent, ref, onMounted, onBeforeUnmount } from "vue";

export default defineComponent({
  name: "Dropdown",
  setup(){
    const dropdown = {
      active: ref(false),
      close: () => {
        dropdown.active.value = false
      }
    }

    onBeforeUnmount(() => {
      document.removeEventListener('click', dropdown.close)
    })

    onMounted(() => {
      document.addEventListener('click', dropdown.close)
    })

    return {
      dropdown
    }
  }
})

</script>

This example uses bulma but off course you don't need to.

You can make use of the blur event, eg if you add a method:

close() {
    setTimeout(() => {
        this.state = false;
    }, 200);
}

And set the blur event for your link:

<a href="#" @click.prevent="toggleDropdown" @blur="close">toggle menu</a>

Then the dropdown will get hidden whenever your toggle link loses focus. The setTimeout is necessary because Javascript click events occur after blur, which would result in your dropdown links being not clickable. To work around this issue, delay the menu hiding a little bit.

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