一个可以手势滑动关闭的 ActionSheet

232 阅读1分钟

此组件基于 Vant ActionSheet 进行二次开发,增加可以手势滑动关闭的功能。 slot 动态渲染

<template>
    <div class="action-sheet">
        <van-action-sheet
            v-bind="$attrs"
            :style="{ bottom: `-${translateY}px` }"
            @click-overlay="handleClickOverlay"
        >
            <div
                class="grabber icon icon-grabber"
                @touchstart="handleTouchStart"
                @touchmove="handleTouchMove"
                @touchend="handleTouchEnd"
            >
            </div>
            <slot v-for="(_, name) in $slots" :name="name"></slot>
        </van-action-sheet>
    </div>
</template>

<script>
export default {
    data() {
        return {
            startY: 0,
            moveY: 0,
            translateY: 0,
            threshold: 50
        };
    },
    watch: {
        '$attrs.value': {
            immediate: true, // 立即执行
            handler(val) {
                if (val) {
                    this.translateY = 0;
                }
            }
        }
    },
    methods: {
        handleTouchStart(event) {
            this.startY = event.touches[0].clientY;
        },

        handleTouchMove(event) {
            this.moveY = event.touches[0].clientY;
            // 计算滑动距离并更新 ActionSheet 的位置
            const distance = this.moveY - this.startY;
            if (distance > 0) {
                this.translateY = distance;
            }
        },

        handleTouchEnd() {
            const distance = this.moveY - this.startY;
            if (distance > this.threshold) {
                this.$emit('close');
            }
            else {
                // 如果滑动距离不够,则恢复原位
                this.translateY = 0;
            }
        },

        handleClickOverlay() {
            this.$emit('close');
        }
    }
};
</script>

<style lang="less" scoped>
    .action-sheet {
        .grabber {
            font-size: 6px;
            text-align: center;
            padding-top: 6px;
            padding-bottom: 10px;
            color: var(--color-content-17);
        }
    }
</style>