I have created a functional demonstration of VUE JS menu animation. However, I am encountering an issue due to having two root elements inside the menu component, resulting in the following warning:
[Vue warn]: Runtime directive used on component with non-element root node. The directives will not function as intended.
App.vue
<script setup>
import { ref } from 'vue'
import Menu from './Menu.vue'
const menuVisible = ref(false)
const toggle = () => {
menuVisible.value = !menuVisible.value
}
</script>
<template>
<h1>Side bar animation</h1>
<button @click="toggle">Toggle menu</button>
<Menu :visible="menuVisible" @update:visible="toggle" v-show="menuVisible"/>
</template>
Menu.vue
<script setup lang="ts">
import { toRefs, watchEffect, onBeforeUnmount, onMounted } from 'vue';
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false
}
});
const { visible } = toRefs(props);
const emit = defineEmits(['update:visible']);
const hidemenuBar = () => {
emit('update:visible', false);
};
watchEffect(() => {
document.body.style.overflow = visible.value ? 'hidden' : 'auto';
document.body.style.paddingRight = visible.value ? '15px' : '0px';
});
onBeforeUnmount(() => {
document.body.style.overflow = 'auto';
document.body.style.paddingRight = '0px';
});
</script>
<template>
<transition name="fade">
<div v-if="visible" class="menubar-overlay" @click="hidemenuBar"></div>
</transition>
<transition name="slide">
<div class="menubar-container" v-if="visible">
<div class="menubar__header">
<h2 class="menu-headline">Menu</h2>
<div>
<i @click="hidemenuBar" class="cursor-pointer pi pi-times p-2"></i>
</div>
</div>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<button @click="hidemenuBar">Close</button>
</div>
</transition>
</template>
<style scoped>
.slide-enter-from,
.slide-leave-to {
transform: translateX(100%);
}
.slide-enter-to,
.slide-leave-from {
transform: translateX(0);
}
.slide-enter-active,
.slide-leave-active {
transition: transform 1s;
}
/* menubar */
.menubar-overlay {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.7);
cursor: pointer;
}
.menubar-container {
position: fixed;
display: grid;
align-items: start;
top: 0;
right: 0;
bottom: 0;
width: 100%;
max-width: 200px;
height: 100%;
overflow: hidden;
overflow-y: auto;
margin-left: auto;
background-color: white;
z-index: 100;
}
.menubar__header {
z-index: 2;
display: flex;
justify-content: space-between;
margin: 20px;
border-bottom: 2px solid black;
}
</style>
Unfortunately, when I enclose the transitions in a template within Menu.vue, the animation ceases to work entirely... while wrapping it in a div only results in one-way functionality (slide-in but no slide-out).
Do you have any suggestions on how to resolve this issue?
Test it out here: here