一个vue3指令,兼容pc与移动端的拖动tab切换,鼠标拖动与触摸拖动触控监听

<View class="app-tabs-container" :class="{ appear: state.showTabsTrans }" v-tabs-pointer-event:[state.hasMove]="handleProductChange">
    <router-view v-slot="{ Component }">
        <KeepAlive>
            <component :is="Component" :key="route.fullPath"></component>
        </KeepAlive>
    </router-view>
</View>
import vTabsPointerEvent from '@/directives/vTabsPointerEvent';

vTabsPointerEvent.ts

const vPointerEvent = {
    mounted(el: HTMLElement, binding: any) {
        const childNum = el.children.length;
        el.style.width = 'max-content';
        const childWidth = Math.floor(el.clientWidth / childNum);
        const emitIndex = binding.value || (() => {});

        /** 未限制最左右侧页面尽头的不可滑动,需添加页面位置标志监听 */
        const discoverTabsType = localStorage.getItem('discoverTabsType') || 'appIndex';
        let startX = 0;
        /** 限制出现上下滑动时禁止切面切换事件 */
        let startY = 0;
        let hasMove = false;
        el.addEventListener('pointerdown', event => {
            event.preventDefault();
            startX = event.pageX;
            startY = event.pageY;
            el.style.transition = '';
        });

        el.addEventListener('pointermove', event => {
            if (event.pointerType === 'mouse' && event.buttons === 0) return event.stopPropagation(); // 鼠标滑过忽略

            const nowOffsetX = event.pageX - startX;
            /** 限制最左右侧页面尽头的不可滑动 */
            if ((discoverTabsType === 'appIndex' && nowOffsetX > 0) || (discoverTabsType === 'appSort' && nowOffsetX < 0)) {
                hasMove = false;
                event.stopPropagation();
                return;
            }
            const nowOffsetY = event.pageY - startY;
            if (Math.abs(nowOffsetX) > 10) hasMove = true;
            if (Math.abs(nowOffsetY) > 20) hasMove = false;
        });

        el.addEventListener('pointerup', event => {
            emitIndex(hasMove);
            if (!hasMove) return event.stopPropagation();
            hasMove = false;
        });

        /** 兼容鼠标拖动的滚动事件 */
        el.addEventListener('mouseleave', event => {
            if (event.pointerType === 'mouse' && event.buttons === 0) return; // 鼠标滑过忽略
            if (!hasMove) return event.stopPropagation();
            emitIndex(hasMove);
            hasMove = false;
        });

        el.addEventListener('touchmove', event => {
            /** 页面可上下滑动 */
            if (hasMove) event.preventDefault();
        });

        el.addEventListener('click', event => {
            /** 监听会在 @click 事件触发后才触发,无法拦截 @click 事件 */
            event.preventDefault();
            /** 滑动有偏移的话就阻止点击事件的捕获 */
            if (Math.abs(startX - event.clientX) > 5) event.stopPropagation();
        });
    }
};

export default vPointerEvent;

posted @ 2024-03-29 11:45  yoona-lin  阅读(169)  评论(0编辑  收藏  举报