vue可復用slide動畫


vue創建可復用的slideUp和slideDown動畫組件

template結構

<template>
    <transition
        name="laoq-transition-collapse"
        mode="out-in"
        @before-enter="beforeEnter"
        @enter="enter"
        @after-enter="afterEnter"
        @before-leave="beforeLeave"
        @leave="leave"
        @after-leave="afterLeave"
    >
        <slot></slot>
    </transition>
</template>

script代碼

<script>
import LaoqUtil from '../../../utils/util';
import './collapse.less';

export default {
    name: 'laoq-transition-collapse',
    data() {
        return {
            animation_ing: false    //記錄當前是否處於動畫中,如果是則切換時跳過動畫,避免頻繁切換時paddingTop和paddingBottom來不及還原導致顯示失真
        };
    },
    methods: {
        beforeEnter(el) {
            //顯示動畫開始的狀態
            if (this.animation_ing) return;

            this.animation_ing = true;
            LaoqUtil.addClass(el, 'laoq-transition-collapse');

            !el.dataset && (el.dataset = {});
            el.dataset.paddingTop = el.style.paddingTop;
            el.dataset.paddingBottom = el.style.paddingBottom;
            el.dataset.overflow = el.style.overflow;
            el.dataset.paddingTopComputed = LaoqUtil.getCSS(el, 'padding-top');
            el.dataset.paddingBottomComputed = LaoqUtil.getCSS(el, 'padding-bottom');

            el.style.height = 0;
            el.style.paddingTop = 0;
            el.style.paddingBottom = 0;
            el.style.overflow = 'hidden';
        },
        enter(el) {
            //顯示動畫結束的狀態
            let scroll_height = el.scrollHeight,
                scroll_height_computed = el.scrollHeight + parseFloat(el.dataset.paddingTopComputed) + parseFloat(el.dataset.paddingBottomComputed);

            /*
             * 元素由隱藏到顯示的過程中,設置的paddingTop和paddingBottom會有延遲
             * 此時取到的scrollHeight可能只是元素內容的高度並不包含paddingTop和paddingBottom,在設置元素的顯示高度時需要判斷一下
* 在style內聯樣式之外的地方設置的paddingTop和paddingBottom通過el.style.paddingTop取不到的,所以需要通過getComputedStyle方法獲取
*/ el.style.height = Math.max(scroll_height, scroll_height_computed) + 'px'; el.style.paddingTop = el.dataset.paddingTop; el.style.paddingBottom = el.dataset.paddingBottom; }, afterEnter(el) { //顯示動畫結束后的收尾工作 LaoqUtil.removeClass(el, 'laoq-transition-collapse'); el.style.height = ''; el.style.overflow = el.dataset.overflow; delete el.dataset.paddingTop; delete el.dataset.paddingBottom; delete el.dataset.overflow; delete el.dataset.paddingTopComputed; delete el.dataset.paddingBottomComputed; this.animation_ing = false; }, beforeLeave(el) { //隱藏動畫開始的狀態 if (this.animation_ing) return; this.animation_ing = true; LaoqUtil.addClass(el, 'laoq-transition-collapse'); !el.dataset && (el.dataset = {}); el.dataset.paddingTop = el.style.paddingTop; el.dataset.paddingBottom = el.style.paddingBottom; el.dataset.overflow = el.style.overflow; el.style.height = el.scrollHeight > 0 ? el.scrollHeight + 'px' : ''; el.style.overflow = 'hidden'; }, leave(el) { //隱藏動畫結束的狀態 el.style.height = el.scrollHeight > 0 ? 0 : ''; el.style.paddingTop = 0; el.style.paddingBottom = 0; }, afterLeave(el) { //隱藏動畫結束后的收尾工作 LaoqUtil.removeClass(el, 'laoq-transition-collapse'); el.style.height = ''; el.style.paddingTop = el.dataset.paddingTop; el.style.paddingBottom = el.dataset.paddingBottom; el.style.overflow = el.dataset.overflow; delete el.dataset.paddingTop; delete el.dataset.paddingBottom; delete el.dataset.overflow; this.animation_ing = false; } } } </script>

util.js

'use strict';

const LaoqUtil = {
    addClass(ele, cls) {
        if (!ele || !cls) return;

        cls = cls.trim();
        let cur_class = ele.className;

        cls.split(' ').forEach(item => {
            if (!item) return true;

            if (ele.classList) {
                ele.classList.add(item);
            } else {
                cur_class += ' ' + item;
            }
        });

        !ele.classList && (ele.className = cur_class);
    },

    removeClass(ele, cls) {
        if (!ele || !cls) return;

        cls = cls.trim();
        let cur_class = ' ' + ele.className + ' ';
        cls.split(' ').forEach(item => {
            if (!item) return true;

            if (ele.classList) {
                ele.classList.remove(item);
            } else {
                cur_class = cur_class.replace(' ' + item + ' ', '');
            }
        });

        !ele.classList && (ele.className = cur_class.trim());
    },

    getCSS(ele, prop) {
        return window.getComputedStyle(ele, null).getPropertyValue(prop) || '';
    }
};

export default LaoqUtil;

collapse.less

.laoq-transition-collapse {
    -webkit-transition: height 0.4s ease-in-out, padding-top 0.4s ease-in-out,
        padding-bottom 0.4s ease-in-out;
    -moz-transition: height 0.4s ease-in-out, padding-top 0.4s ease-in-out,
        padding-bottom 0.4s ease-in-out;
    transition: height 0.4s ease-in-out, padding-top 0.4s ease-in-out,
        padding-bottom 0.4s ease-in-out;
}

 

測試

<template>
    <div>
        <div style="margin:20px 0;">
            <laoq-button @click="click">slide</laoq-button>
        </div>

        <laoq-transition-collapse>
            <div class="main" v-show="show">
                我是DIV<br/>我是DIV<br/>我是DIV<br/>
            </div>
        </laoq-transition-collapse>
    </div>
</template>

<script>
import LaoqTransitionCollapse from '../components/transition/collapse/collapse.vue';

export default {
    components:{
        LaoqTransitionCollapse
    },
    data() {
        return {
            show: true
        };
    },
    methods: {
        click() {
            this.show = !this.show;
        }
    }
}
</script>

<style lang="less" scoped>
.main {
    width: 200px;
    padding:50px;
    text-align: center;
    color: #fff;
    background: #17a2b8;
}
</style>

效果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM