N
Nuxt17mo ago
Henrik

useElementVisibility in custom directive always returns false

I'm building a custom directive with useElementVisibility but it always returns false for every element regardless if it is in the viewport or not. It kind of worked with @vueuse/core and @vueuse/nuxt in version 9 but after upgrading to 10 it stopped working completely. The problem in version 9 was that it return correct state on page load but after route change it always returned true. Has anyone tried this and know how to work with useElementVisibility in a custom directive?
<template>
<div v-visibility/>
</template>

export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive('visibility', {
mounted(el) {
if (useElementVisibility(el).value) {
el.classList.add('visible');
);
}
});
});
<template>
<div v-visibility/>
</template>

export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive('visibility', {
mounted(el) {
if (useElementVisibility(el).value) {
el.classList.add('visible');
);
}
});
});
4 Replies
Cue
Cue17mo ago
Ensure you update vueuse to 10.1.0. Initial release of 10 had bugs in useIntersectionObserver composable which is used by useElementVisibility.
Henrik
Henrik17mo ago
Both packages are on 10.1.0
Cue
Cue17mo ago
Ah. The return value is false by default, my guess is your directive is reading the value before it is updated by IntersectionObserver. You can track the change by watching the value, and updating the class accordingly. For example:
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive('visibility', {
mounted(el) {
const isVisible = useElementVisibility(el)

watch(isVisible, value => el.classList[value ? 'add' : 'remove']('visible'), { immediate: true })
}
})
})
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive('visibility', {
mounted(el) {
const isVisible = useElementVisibility(el)

watch(isVisible, value => el.classList[value ? 'add' : 'remove']('visible'), { immediate: true })
}
})
})
Henrik
Henrik16mo ago
Wonderful, will give that a go. Thank you! Adding a small timeout fixes the issue in my use case. It is not optimal since it has to be matched with timing of page transitions but even without a page transition a small delay is necessary to get an accurate value.
<template>
<div v-visibility/>
</template>

export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive('visibility', {
mounted(el) {

setTimeout(() => {
if (useElementVisibility(el).value) {
el.classList.add('visible');
}
}, 250);

}
});
});
<template>
<div v-visibility/>
</template>

export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive('visibility', {
mounted(el) {

setTimeout(() => {
if (useElementVisibility(el).value) {
el.classList.add('visible');
}
}, 250);

}
});
});
js
Want results from more Discord servers?
Add your server