First things first I use the <script setup>
API.
In Vuetify components like v-menu
have a slot called activator
where you can put a custom element as your dropdown "button" and bind the onClick
listener by v-binding the props passed to that slot from inside the v-menu
component like so:
<v-menu>
<template #activator="{ props: activatorProps }">
<v-btn v-bind="activatorProps">Expand me</v-btn>
</template>
<v-list>
<v-list-item>1</v-list-item>
<v-list-item>1</v-list-item>
<v-list-item>1</v-list-item>
</v-list>
</v-menu>
How can I create such component with a slot that has @click
binded to it from inside the component so I can "bind" the @click
event to the element I pass to that slot?
Here is my in-progress dropdown component:
<template>
<div :class="$style['dropdown']">
<slot name="activator" @click="expand">
</slot>
<div :class="$style['dropdown__content']">
<a href="">Item1</a>
<a href="">Item2</a>
<a href="">Item3</a>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from "vue"
import { ref } from "vue"
const props = defineProps<{
backgroundColor?: string
}>()
const expanded = ref(false)
const menuDisplayCssProp = computed(() => expanded.value ? "block" : "none")
const expand = () => {
expanded.value = !expanded.value
}
</script>
<style module lang="scss">
.dropdown {
button {
cursor: pointer;
}
a {
display: block;
text-decoration: none;
}
&__content {
display: v-bind(menuDisplayCssProp);
position: absolute;
background-color: v-bind(backgroundColor);
}
}
</style>
I want to be able to use it the same way as Vuetify's v-menu
:
<AppDropdown>
<template #activator="{ props: activatorProps }">
<button type="button" v-bind="activatorProps">Expand me</button>
</template>
</AppDropdown>
AppDropdown.vue:
<template>
<div>
<slot name="activator" :props="activatorProps" :expanded="expanded"></slot>
<slot name="content" v-if="expanded"></slot>
</div>
</template>
<script setup>
import { ref } from 'vue'
const expanded = ref(false)
const activatorProps = ref({
onclick: () => {
expanded.value = !expanded.value
},
})
</script>
Usage:
<template>
<AppDropdown>
<template #activator="{ props, expanded }">
<button v-bind="props">{{ expanded ? 'Hide' : 'Show' }}</button>
</template>
<template #content>
<div>Hi!</div>
</template>
</AppDropdown>
</template>
<script setup>
import AppDropdown from './AppDropdown.vue'
</script>