I have this sample of code
Parent:
<template>
<div>
<button @click="cartToggle">Toggle</button>
</div>
<div>
<Child
:visible="cartVisible"
@update:visible="cartToggle"
v-show="cartVisible"
/>
</div>
</template>
<script setup>
import { ref } from "vue";
import Child from "./Child.vue";
const cartVisible = ref(false);
const cartToggle = () => {
cartVisible.value = !cartVisible.value;
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
span {
cursor: pointer;
}
</style>
Child:
<script setup lang="ts">
import { toRefs, watchEffect, onBeforeUnmount } from "vue";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
});
const { visible } = toRefs(props);
const emit = defineEmits(["update:visible"]);
const hideCartBar = () => {
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>
<div class="cartbar">
<div class="cartbar-wrapper">
<transition name="fade">
<div
v-show="props.visible"
class="cartbar-overlay"
@click="hideCartBar"
></div>
</transition>
<transition name="slide">
<div v-show="props.visible" class="cartbar-container">
<div class="cartbar__header">
<h2>Menu</h2>
<span @click="hideCartBar" class="cursor-pointer">Close</span>
</div>
</div>
</transition>
</div>
</div>
</template>
<style scoped>
/* transition */
/* transition */
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.fade-enter-to,
.fade-leave-from {
opacity: 1;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 500ms;
}
.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 500ms;
}
/* cartbar */
.cursor-pointer {
cursor: pointer;
}
.cartbar-wrapper {
transition: visibility 0s 0s;
z-index: 1300;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
width: 100%;
padding-left: calc(4px * 9);
}
.cartbar-overlay {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.7);
opacity: 1;
cursor: pointer;
}
.cartbar-container {
position: relative;
display: flex;
flex-direction: column;
width: 100%;
max-width: 460px;
height: 100%;
overflow: hidden;
margin-left: auto;
padding: calc(4px * 7);
background-color: #f4f2f1;
color: #706b5f;
}
</style>
and the problem is, when I want to toggle the menu in .. it slides in fine, but it doesn't slide out ... plus - the overlay does not animate at all
what am I doing wrong?
The v-show="cartVisible"
on the Child removes the whole element before the out-transition even starts. But when simply removing the v-show
, the .cartbar-wrapper
will overlay the whole screen, making it impossible to press the button. You'll have to change the structure of the Child component so that it works without a container.
A simple solution would be to just remove the wrapper and put the position:fixed
on the .cartbar-container
, have a look a the playground.