Skip to content

Instantly share code, notes, and snippets.

@lifo101
Last active November 7, 2017 19:05
Show Gist options
  • Save lifo101/0e7c75c098f850ea6ec07b2b35785111 to your computer and use it in GitHub Desktop.
Save lifo101/0e7c75c098f850ea6ec07b2b35785111 to your computer and use it in GitHub Desktop.
Vue2 "slide" transition for sliding elements of any height up/down (like jQuery.slideDown()) w/o the need to use a max-height hack
<script>
/**
* Creates a "slide" transition that will slide up/down the content within an element, no matter it's height.
* Some other solutions use max-height but that causes an annoying 'delay' due to having to use a large max-height
* value.
*
* This technique uses the element's "scrollHeight" and adjusts the elements height automatically. So you get a
* perfect slide effect w/o any delays.
*
* Usage:
* <transition-slide>
* <div v-if="show">some content here... can be any height (or even 'auto')</div>
* </transition-slide>
*/
export default {
props: {
name: {'default': 'slide'},
mode: {'default': 'out-in'},
duration: {'default': undefined},
},
methods: {
onBeforeEnter(el) {
el.style.display = 'block';
el.style.overflow = 'hidden';
el.style.height = 0;
},
onBeforeLeave(el) {
el.style.display = 'block';
el.style.overflow = 'hidden';
el.style.height = el.style.height || (el.scrollHeight + 'px');
},
onEnter(el) {
el.style.height = el.scrollHeight + 'px';
},
onLeave(el) {
// not sure why I need a timeout to make it work properly. Otherwise the height is applied too
// soon and the transition doesn't take effect. I tried $nextTick and it still didn't work.
setTimeout(function () {
el.style.height = 0;
}, 1);
},
onAfter(el) {
el.style.overflow = '';
el.style.height = '';
},
}
}
</script>
<template>
<transition :name="name" :duration="duration" :mode="mode"
@before-enter="onBeforeEnter"
@after-enter="onAfter"
@enter="onEnter"
@before-leave="onBeforeLeave"
@after-leave="onAfter"
@leave="onLeave">
<slot></slot>
</transition>
</template>
<style lang="less">
.slide-enter-active, .slide-leave-active {
transition: all .5s;
}
.slide-enter, .slide-leave-to {
overflow: hidden;
display: block;
opacity: 0;
}
.slide-enter-to, .slide-leave {
opacity: 1;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment