手机端实现触摸拖拽效果

6 篇文章 0 订阅
2 篇文章 0 订阅

手机端实现触摸拖拽效果

前言

相信在开发手机端页面时,大家都会碰到拖拽元素的需求,下面我们就来介绍一下相关的实现过程,我们需要使用到touchstart,touchmove,touchend三个事件,

1.touchstart是触摸开始时触发的事件
2.touchmove是触摸移动过程中触发的事件
3.touchend是触摸结束时触发的事件

我们遇到这样一个需求,初始状态,底部会展示一小部分区域,当我们手指触摸到上面时,向上滑动,底部区域会随着手指移动而跟着向上移动,分为以下优化情况
1.当在底部时,快速向上滚动然后放开,底部应该正常的向上滚动到顶部,
2.当在底部时,缓慢向上滚动然后停止一段时间然后放开,应该根据停止的位置进行是回到底部还是到顶部
3.当在顶部时,快速向下滚动然后放开,应该正常的向下滚动到底部,
4.当在顶部时,缓慢向下滚动然后停止一段时间然后放开,应该根据停止的位置进行是回到底部还是到顶部
在这里插入图片描述
在这里插入图片描述
这里有三块,1.首页,2.底部区域,3.底部内

难点,底部区域初始态,底部区域滚动过程态,底部区域滚动终止态

底部区域初始态:首页要可滚动,底部区域要可触发,底部内要不可滚动
底部区域滚动过程态:当底部区域进行触摸跟随移动时,需要阻止首页的滚动,也需要阻止底部内的滚动,因为事件冒泡会触发滚动和触摸事件
底部区域滚动终止态:当底部区域移动到最上方时,底部内就需要可以进行滚动,

2.1当手指向上滚动时,需要阻止底部区域的触摸事件不触发,只触发底部内的滚动事件
2.2当手指向下滚动时,指直到无法在进行滚动,已经滚动到最顶部了,需要触发底部区域的触摸事件,阻止底部内的滚动事件

下图是移动到最上方的状态
在这里插入图片描述

下面是我们具体实现代码

//html代码
    <div
        id="dialogWrap"
        :class="['dialogWrap', showBoard ? 'active' : 'normal']"
        @touchstart="dialogWrapStart"
        @touchmove="dialogWrapMove"
        @touchend="dialogWrapEnd"
    >
        <div class="dialogHeader">
            <div class="headerLine"></div>
        </div>
         <div id="dialogContent"
             class="dialogContent"
             @scroll="dialogContentScroll">
         </div>
    </div>
//js代码
   //定义datas
    flags = false;
    position = { x: 0, y: 0 };
    nx = 0;
    ny = 0;
    dx = 0;
    dy = 0;
    xPum = 0;
    yPum = 0;
    beforePum = 0; //移动前一刻位置
    pausePum = 0;//移动暂停时位置
    isTouchStart = false;//是否开始触摸事件
    bottomHeight = 0; // 底部高度
    //底部内
     private get dialogContent(): HTMLElement {
        return document.getElementById('dialogContent');
    }
    //底部区域
    private get dialogWrap(): HTMLElement {
        return document.getElementById('dialogWrap');
    }
    //首页
    private get bodyEle(): HTMLElement {
        return document.body;
    }
    mounted(): void {
        this.bottomHeight = window.innerHeight / (window.innerWidth / 3.6) - 1.19;
    }
    //内部滚动
    private dialogContentScroll(e): void {
        e.stopPropagation();
        let scrollTops = Math.ceil(this.dialogContent.scrollTop); //滚动的距离
        let clientHeight = this.dialogContent.clientHeight; //窗口的高度
        let scrollHeight = this.dialogContent.scrollHeight; //内容的总高度
        // console.log('--------------------', 0, scrollTops, clientHeight, scrollHeight);
        if (scrollTops === 0) {
          // 滚动到最上方时,变为false,可以触发底部区域的触摸事件
            this.isTouchStart = false;
        } else {
        // 除了滚动到最上方时,变为true,不可以触发底部区域的触摸事件
            this.isTouchStart = true;
        }
    }

    //触摸开始
    private dialogWrapStart(event): void {
        event.stopPropagation();
        if (this.isTouchStart) {
            return;
        }
        this.bodyEle.style.overflow = 'hidden';  //阻止首页滚动
        this.dialogContent.style.overflow = 'hidden';  //阻止底部内滚动
        this.dialogWrap.style.transition = null;
        this.flags = true;
        let touch;
        if (event.touches) {
            touch = event.touches[0];
        } else {
            touch = event;
        }
        this.position.x = touch.clientX;
        this.position.y = touch.clientY;
        this.dx = this.dialogWrap.offsetLeft;
        this.dy = this.dialogWrap.offsetTop;
    }
    //触摸移动
    private dialogWrapMove(event): void {
        event.stopPropagation();
        if (this.flags) {
            let touch;
            if (event.touches) {
                touch = event.touches[0];
            } else {
                touch = event;
            }
            this.nx = touch.clientX - this.position.x;
            this.ny = touch.clientY - this.position.y;
            this.xPum = this.dx + this.nx;
            this.yPum = this.dy + this.ny;
            setTimeout(() => {
                this.beforePum = this.yPum - 1;
                this.pausePum = this.yPum;
            }, 10);
            if (this.yPum >= 50 && this.yPum <= 650) {
                this.dialogWrap.style.top = this.yPum + 'px';
            }
            // console.log(this.yPum);
            if (this.yPum <= 600) {
                //滚动到一定距离,加载后面的模块,性能优化初始状态只加载底部区域的部分内容
                this.isScroll = true;
            }
            //阻止页面的滑动默认事件;如果碰到滑动问题,1.2 请注意是否获取到 touchmove
            document.addEventListener(
                'touchmove',
                function () {
                    event.preventDefault();
                },
                false
            );
        }
    }
    // 向上的滚动
    private handelTop(): void {
         this.dialogWrap.style.top = 0.5 + 'rem';
         this.dialogContent.style.overflow = 'scroll';//开启底部内滚动
         this.$emit('showDialog');
        this.isScroll = true;
    }

    // 向下的滚动
    private handelBottom(): void {
            this.dialogWrap.style.top = this.bottomHeight + 'rem';
            this.dialogContent.style.overflow = 'hidden';//阻止底部内滚动
            this.bodyEle style.overflow = 'scroll';  //开启首页滚动
            this.$emit('hideDialog');
    }
    //触摸结束
    private dialogWrapEnd(): void {
        this.flags = false;
        if (this.isTouchStart) {
            return;
        }
        this.dialogWrap.style.transition = 'top 0.3s';
        console.log('this.yPum', this.yPum, 'this.beforePum', this.beforePum, this.pausePum, Math.abs(this.xPum));
        if (this.yPum < this.beforePum) {
            //当this.yPum小于this.beforePum时,当手指迅速向上滑动
            this.handelTop();
        }else if(this.yPum == this.pausePum) {
            //当this.yPum等于this.beforePum时,也就是滚动到中间停止一段时间的情况
            //根据this.yPum是否滚动距离超过一半来,区分是向上还是向下
            if(this.yPum >= 330 && this.dialogWrap.style.top !== '0.5rem') {
                this.handelBottom();
            }else if (this.yPum <= 330 && this.yPum > 0) {
                this.handelTop();
            }
        } else if(this.yPum > this.beforePum) {
            //当this.yPum大于this.beforePum时,当手指迅速向下滑动
            if(Math.abs(this.xPum) >= 30) {
                //当水平位移大于30,向上,为了防止banner水平位移导致的向下收起面板
                this.handelTop();
            }else {
                this.handelBottom();
            }
        }
        console.log(this.yPum, 2);
        this.flags = false;
    }
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值