I'm getting the width of the HTML element which is passed as slot like this:
<template>
<div>
<button @mouseover="state.show = true" @mouseleave="state.show = false">
hover me
</button>
<div v-if="state.show">
<slot name="test"></slot>
</div>
</div>
</template>
<script setup>
import { reactive, watch, useSlots, nextTick } from 'vue'
const slots = useSlots();
const state = reactive({
show: false
})
watch(() => state.show, () => {
if (state.show) {
nextTick(() => {
console.log(slots.test()[0].el.offsetWidth)
})
}
})
</script>
This print correct value only on first hover of button. When hovered more than one time, it logs 0
. Why? How to get width of <slot name="test"></slot>
every time I hover button?
I also tried with getBoundingClientRect()
on onUpdated
vue hook which is executed after DOM changes:
<script setup>
import { reactive, watch, useSlots, nextTick, onUpdated } from 'vue'
const slots = useSlots();
const state = reactive({
show: false
})
onUpdated(() => {
if (state.show && slots.test() && slots.test()[0] && slots.test()[0].el) {
console.log(slots.test()[0].el.getBoundingClientRect())
}
})
</script>
With the same result - it shows correct width only on first hover. Playground with this example
Thank you @tao for your input but the real solution is different. Changing between v-show and v-if is changing the actual logic of the script which I don't want - I want to completly remove element from DOM therefore I'll use v-if.
However as pointed by vue team this is usage issue not vue bug. In order to achieve what I wanted I need to use render function.
<template>
<div>
<button @mouseover="state.show = true" @mouseleave="state.show = false">
hover me
</button>
<div v-if="state.show">
<RenderTestSlot />
</div>
</div>
</template>
<script setup>
import { reactive, watch, useSlots, nextTick, computed, h, Fragment } from 'vue'
const slots = useSlots();
const state = reactive({
show: false
})
const RenderTestSlot = computed(() => h(Fragment, slots.test ? slots.test() : []));
watch(() => state.show, () => {
if (state.show) {
nextTick(() => {
console.log(RenderTestSlot.value.children[0].el.offsetWidth)
})
}
})
</script>