funkhaus / fh-components

Reusable components for Vue + Vuehaus
18 stars 1 forks source link

Switch TransitionSlideToggle to vanilla #75

Closed SaFrMo closed 5 years ago

SaFrMo commented 6 years ago

Super useful component, but now that we're using Velocity a bit less, it adds a good amount of weight. I started this but haven't had time to finish yet:

<template>
    <transition
        @enter="enter"
        @leave="leave"
        :css="false">

        <slot />

    </transition>
</template>

<script>
import Vue from 'vue'
import { tween } from 'shifty'

export default {
    data() {
        return {
            targetHeight: 0,
            tween: null,
            displayHeight: 0
        }
    },
    props: {
        speed: {
            type: Number,
            default: 400
        }
        // easing: {
        //     type: String,
        //     default: 'swing'
        // }
    },
    methods: {
        calculateHeight() {
            // save old style values
            const old = {
                position: this.$el.style['position'],
                visiblity: this.$el.style['visibility']
            }

            // hide element and remove from flow to measure height
            this.$el.style['position'] = 'absolute'
            this.$el.style['visibility'] = 'hidden'

            // save target height
            const height = this.$el.offsetHeight

            this.$el.style['position'] = old.position
            this.$el.style['visibility'] = old.visibility || 'visible'

            return height
        },
        async enter(el, done) {
            // wait for slot to exist in DOM
            await Vue.nextTick()

            // calculate target height
            const height = this.calculateHeight()

            await tween({
                from: { h: 0 },
                to: { h: height },
                step: state => {
                    this.displayHeight = state.h

                    const elem = _get(this, '$slots.default[0].elm', {
                        style: {}
                    })

                    elem.style.height = `${state.h}px`
                }
            })

            // proxy event
            this.$emit('enter', ...arguments)

            done()
        },
        async leave(el, done) {
            console.log(this)
            const elem = _get(this, '$slots.default[0].elm')

            await tween({
                from: { h: elem.offsetHeight },
                to: { h: 0 },
                step: state => {
                    const elem = _get(this, '$slots.default[0].elm', {
                        style: {}
                    })

                    el.style.height = `${state.h}px`
                }
            })

            done()

            // proxy event
            this.$emit('leave', ...arguments)
        }
    }
}
</script>

<style lang="scss">
</style>
SaFrMo commented 5 years ago

Closing since this is a pretty specific solution to a problem that doesn't crop up that much any more.