On gists
Accordion
Vue.js
Accordion.vue
Raw
#
<template>
<ul>
<slot></slot>
</ul>
</template>
<script>
export default {
props: {},
data() {
return {
AccordionState: {
count: 0,
active: 1
}
}
},
provide() {
return { AccordionState: this.AccordionState }
}
}
</script>
<style lang="scss" scoped></style>
AccordionItem.vue
Raw
#
<template>
<li class="AccordionItem" :class="{ '-Expanded': visible }">
<div @click="open">
<slot name="header"></slot>
</div>
<transition
name="accordion"
@enter="startTransition"
@after-enter="endTransition"
@before-leave="startTransition"
@after-leave="endTransition"
>
<div class="accordion__content" v-show="visible">
<slot name="content"></slot>
</div>
</transition>
</li>
</template>
<script>
export default {
props: {},
inject: ['AccordionState'],
data() {
return {
index: null
}
},
computed: {
visible() {
return this.index == this.AccordionState.active
}
},
methods: {
open() {
if (this.visible) {
this.AccordionState.active = null
} else {
this.AccordionState.active = this.index
}
},
startTransition(el) {
el.style.height = el.scrollHeight + 'px'
},
endTransition(el) {
el.style.height = ''
}
},
created() {
this.index = ++this.AccordionState.count
}
}
</script>
<style lang="scss" scoped>
.accordion-enter-active,
.accordion-leave-active {
will-change: height, opacity;
transition: height 0.2s ease, opacity 0.2s ease;
overflow: hidden;
}
.accordion-enter-from,
.accordion-leave-to {
height: 0 !important;
opacity: 0;
}
</style>