slide-select-swipe.vue 4.92 KB
<template>
  <div class="select-swipe"
        v-touch:panmove="panmove" 
        v-touch:panstart="panstart"
        v-touch:panend="panend">
    <div class="select-foucs"></div>
    <ul class="select-ul"
        :style="selectStyle">
        <li class="item" :class="itemClass(size)" v-for="size in slides" :key="size.id">
            <p>{{size.text}}</p>
        </li>
    </ul>
</div>
</template>

<script>
module.exports = {
    name: 'slide-select-swipe',
    props: {
        slides: {
            type: Array,
            default() {
                return [];
            }
        },
        model: {
            type: Number,
            default: 0
        }
    },
    data() {
        return {
            selectStyle: {
                transform: 'translate(0, 0)',
            },
            transitionStyle: '',
            translateY: 0,
            currentIndex: 2,
            itemHeight: 0,
        };
    },
    methods: {
        renderModel() {
            if (this.model > 0) {
                this.currentIndex = this.slides.findIndex(slide => slide.id === this.model);
            } else {
                if (this.slides.length > 3) {
                    this.currentIndex = 2;
                } else {
                    this.currentIndex = 0;
                }
            }
            this.$emit('change', this.slides[this.currentIndex].id);
            this.$nextTick(() => {
                this.itemHeight = document.querySelector('.select-ul .item').clientHeight;
                this.translateY = 0 - this.currentIndex * this.itemHeight;
                this.transform();
            });
        },
        transform() {
            this.selectStyle.transform = `translate(0px, ${this.translateY + this.itemHeight * 2}px)`;
            this.selectStyle.transition = this.transitionStyle;
        },
        itemClass(slide) {
            let cls = {};
            let slideIndex = this.slides.findIndex(s => s === slide);

            if (this.currentIndex === slideIndex) {
                cls.current = true;
            } else if (this.currentIndex - slideIndex === 1) {
                cls['current-prev'] = true;
            } else if (this.currentIndex - slideIndex === -1) {
                cls['current-next'] = true;
            } else if (this.currentIndex > slideIndex) {
                cls.prev = true;
            } else {
                cls.next = true;
            }
            return cls;
        },
        panstart() {
            this.originY = 0 - this.currentIndex * this.itemHeight;
            this.transitionStyle = '';
            this.selectStyle['will-change'] = 'transform';
            this.transform();
        },
        panmove(e) {
            this.translateY = e.deltaY / 1.5 + this.originY;
            if (this.translateY > 0) {
                this.currentIndex = 0;
            } else {
                this.currentIndex = Math.abs(Math.round(this.translateY / this.itemHeight));
                if (this.currentIndex >= this.slides.length) {
                    this.currentIndex = this.slides.length - 1;
                }
            }
            this.transform();
        },
        panend() {
            this.translateY = 0 - this.currentIndex * this.itemHeight;
            this.transitionStyle = 'transform 0.5s cubic-bezier(0.4, 0, 0.2, 1)';
            delete this.selectStyle['will-change'];
            this.$emit('change', this.slides[this.currentIndex].id);
            this.transform();
        },
    },
    watch: {
        slides(val) {
            this.slides = val;
            this.renderModel();
        }
    },
};
</script>

<style>
$item-height: 68px;

.select-swipe {
    width: 100%;
    height: 340px;
    margin-top: 46px;
    position: relative;
    overflow: hidden;

    .select-foucs {
        width: 100%;
        height: $item-height;
        margin-top: calc(2 * $item-height);
        border-top: 1px solid #e0e0e0;
        border-bottom: 1px solid #e0e0e0;
    }

    .select-ul {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;

        .item {
            width: 100%;
            float: left;
            height: $item-height;
            text-align: center;

            p {
                transition: transform 0.1s linear;
                line-height: $item-height;
                font-size: 32px;
            }

            &.current p {
                transform: rotateX(0deg);
                color: #000;
            }

            &.current-prev p {
                transform: rotateX(10deg) translate(0, -5px);
                color: #b0b0b0;
            }

            &.current-next p {
                transform: rotateX(-10deg) translate(0, 5px);
                color: #b0b0b0;
            }

            &.prev p {
                transform: rotateX(25deg);
                color: #d9d9d9;
            }

            &.next p {
                transform: rotateX(-25deg);
                color: #d9d9d9;
            }
        }
    }
}
</style>