<template>
    <view v-if="isShow" ref="ani" class="uni-transition" :class="[ani.in]" :style="'transform:' +transform+';'+stylesObject"
     @click="change">
         <slot></slot>
    </view>
</template>

<script>
    // #ifdef APP-NVUE
    const animation = uni.requireNativePlugin('animation');
    // #endif
    /**
     * Transition 过渡动画
     * @description 简单过渡动画组件
     * @tutorial https://ext.dcloud.net.cn/plugin?id=985
     * @property {Boolean} show = [false|true] 控制组件显示或隐藏
     * @property {Array} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型
     *  @value fade 渐隐渐出过渡
     *  @value slide-top 由上至下过渡
     *  @value slide-right 由右至左过渡
     *  @value slide-bottom 由下至上过渡
     *  @value slide-left 由左至右过渡
     *  @value zoom-in 由小到大过渡
     *  @value zoom-out 由大到小过渡
     * @property {Number} duration 过渡动画持续时间
     * @property {Object} styles 组件样式,同 css 样式,注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red`
     */
    export default {
        name: 'uniTransition',
        props: {
            show: {
                type: Boolean,
                default: false
            },
            modeClass: {
                type: Array,
                default () {
                    return []
                }
            },
            duration: {
                type: Number,
                default: 300
            },
            styles: {
                type: Object,
                default () {
                    return {}
                }
            }
        },
        data() {
            return {
                isShow: false,
                transform: '',
                ani: { in: '',
                    active: ''
                }
            };
        },
        watch: {
            show: {
                handler(newVal) {
                    if (newVal) {
                        this.open()
                    } else {
                        this.close()
                    }
                },
                immediate: true
            }
        },
        computed: {
            stylesObject() {
                let styles = {
                    ...this.styles,
                    'transition-duration': this.duration / 1000 + 's'
                }
                let transfrom = ''
                for (let i in styles) {
                    let line = this.toLine(i)
                    transfrom += line + ':' + styles[i] + ';'
                }
                return transfrom
            }
        },
        created() {
            // this.timer = null
            // this.nextTick = (time = 50) => new Promise(resolve => {
            //     clearTimeout(this.timer)
            //     this.timer = setTimeout(resolve, time)
            //     return this.timer
            // });
        },
        methods: {
            change() {
                this.$emit('click', {
                    detail: this.isShow
                })
            },
            open() {
                clearTimeout(this.timer)
                this.isShow = true
                this.transform = ''
                this.ani.in = ''
                for (let i in this.getTranfrom(false)) {
                    if (i === 'opacity') {
                        this.ani.in = 'fade-in'
                    } else {
                        this.transform += `${this.getTranfrom(false)[i]} `
                    }
                }
                this.$nextTick(() => {
                    setTimeout(() => {
                        this._animation(true)
                    }, 50)
                })

            },
            close(type) {
                clearTimeout(this.timer)
                this._animation(false)
            },
            _animation(type) {
                let styles = this.getTranfrom(type)
                // #ifdef APP-NVUE
                if(!this.$refs['ani']) return
                animation.transition(this.$refs['ani'].ref, {
                    styles,
                    duration: this.duration, //ms
                    timingFunction: 'ease',
                    needLayout: false,
                    delay: 0 //ms
                }, () => {
                    if (!type) {
                        this.isShow = false
                    }
                    this.$emit('change', {
                        detail: this.isShow
                    })
                })
                // #endif
                // #ifndef APP-NVUE
                this.transform = ''
                for (let i in styles) {
                    if (i === 'opacity') {
                        this.ani.in = `fade-${type?'out':'in'}`
                    } else {
                        this.transform += `${styles[i]} `
                    }
                }
                this.timer = setTimeout(() => {
                    if (!type) {
                        this.isShow = false
                    }
                    this.$emit('change', {
                        detail: this.isShow
                    })

                }, this.duration)
                // #endif

            },
            getTranfrom(type) {
                let styles = {
                    transform: ''
                }
                this.modeClass.forEach((mode) => {
                    switch (mode) {
                        case 'fade':
                            styles.opacity = type ? 1 : 0
                            break;
                        case 'slide-top':
                            styles.transform += `translateY(${type?'0':'-100%'}) `
                            break;
                        case 'slide-right':
                            styles.transform += `translateX(${type?'0':'100%'}) `
                            break;
                        case 'slide-bottom':
                            styles.transform += `translateY(${type?'0':'100%'}) `
                            break;
                        case 'slide-left':
                            styles.transform += `translateX(${type?'0':'-100%'}) `
                            break;
                        case 'zoom-in':
                            styles.transform += `scale(${type?1:0.8}) `
                            break;
                        case 'zoom-out':
                            styles.transform += `scale(${type?1:1.2}) `
                            break;
                    }
                })
                return styles
            },
            _modeClassArr(type) {
                let mode = this.modeClass
                if (typeof(mode) !== "string") {
                    let modestr = ''
                    mode.forEach((item) => {
                        modestr += (item + '-' + type + ',')
                    })
                    return modestr.substr(0, modestr.length - 1)
                } else {
                    return mode + '-' + type
                }
            },
            // getEl(el) {
            //     console.log(el || el.ref || null);
            //     return el || el.ref || null
            // },
            toLine(name) {
                return name.replace(/([A-Z])/g, "-$1").toLowerCase();
            }
        }
    }
</script>

<style>
    .uni-transition {
        transition-timing-function: ease;
        transition-duration: 0.3s;
        transition-property: transform, opacity;
    }

    .fade-in {
        opacity: 0;
    }

    .fade-active {
        opacity: 1;
    }

    .slide-top-in {
        /* transition-property: transform, opacity; */
        transform: translateY(-100%);
    }

    .slide-top-active {
        transform: translateY(0);
        /* opacity: 1; */
    }

    .slide-right-in {
        transform: translateX(100%);
    }

    .slide-right-active {
        transform: translateX(0);
    }

    .slide-bottom-in {
        transform: translateY(100%);
    }

    .slide-bottom-active {
        transform: translateY(0);
    }

    .slide-left-in {
        transform: translateX(-100%);
    }

    .slide-left-active {
        transform: translateX(0);
        opacity: 1;
    }

    .zoom-in-in {
        transform: scale(0.8);
    }

    .zoom-out-active {
        transform: scale(1);
    }

    .zoom-out-in {
        transform: scale(1.2);
    }
</style>