在Vue中实现 兼容PC端下拉操作和移动端下拉操作 的思路


1. html

<template>
    <div class="ebook-reader">
        <div id="read"></div>
        <div class="ebook-reader-mask"
            @click="onMaskClick"
            @touchmove="move"
            @touchend="moveEnd"
            @mousedown.left="onMouseEnter"
            @mousemove.left="onMouseMove"
            @mouseup.left="onMouseEnd"
        ></div>
        <!-- 兼容PC端下拉操作和移动端下拉操作写法: .left事件修饰符表示按下鼠标左键 -->
    </div>
</template>

2. js

export default {
    mixins: [ebookMixin],
    /* 使用vue里的mixin机制优化重复代码,方便统一维护
    computed: {
        ...mapGetters([
            'fileName',
            'menuVisible'
        ])
    },
    */
    methods: {
        /** this.mouseState:
         * 1 - 鼠标进入
         * 2 - 鼠标进入后的移动
         * 3 - 鼠标从移动状态松手
         * 4 - 鼠标还原  (4表示的是点击事件)
         */
        // 鼠标进入
        onMouseEnter(e) {
            this.mouseState = 1
            this.mouseStartTime = e.timeStamp
            e.preventDefault()
            e.stopPropagation()
        },
        // 鼠标移动
        onMouseMove(e) {
            if (this.mouseState  === 1) {
                this.mouseState = 2
            } else if (this.mouseState === 2) {
                let offsetY = 0
                /** 如果第一次的Y轴偏移量存在,则根据当前的Y轴偏移量计算出下拉的距离,存入vuex中 */
                if (this.firstOffsetY) {
                    offsetY = e.clientY - this.firstOffsetY
                    this.setOffsetY(offsetY)
                } else {
                    /** 如果第一次的Y轴偏移量不存在,则设置第一次的Y轴偏移量  */
                    this.firstOffsetY = e.clientY   // 在鼠标事件中,直接通过e.clientY获取鼠标Y轴的位置
                }
            }
            e.preventDefault()
            e.stopPropagation()
        },
        // 鼠标事件结束
        onMouseEnd(e) {
            if (this.mouseState === 2) {
                /** 当onMouseEnd的时候,如果mouseState为2,说明经历过了onMouseMove事件 */
                this.setOffsetY(0)
                this.firstOffsetY = null 
                this.mouseState = 3
            } else {
                /** 当onMouseEnd的时候,如果mouseState不为2,说明没有经历过了onMouseMove事件,则判定为点击事件 */
                this.mouseState = 4
            }

            /** 当从onMouseEnter到onMouseEnd两次的事件小于200ms的时候,也认为是点击事件 */
            const time = e.timeStamp - this.mouseStartTime
            if (time < 200) {
                this.mouseState = 4
            }

            e.preventDefault()
            e.stopPropagation()
        },
        // 触摸下拉事件
        move(e) {
            let offsetY = 0
            /** 如果第一次的Y轴偏移量存在,则根据当前的Y轴偏移量计算出下拉的距离,存入vuex中 */
            if (this.firstOffsetY) {
                offsetY = e.changedTouches[0].clientY - this.firstOffsetY
                this.setOffsetY(offsetY)
            } else {
                /** 如果第一次的Y轴偏移量不存在,则设置第一次的Y轴偏移量  */
                this.firstOffsetY = e.changedTouches[0].clientY       // 在移动端touchmove事件中,需要通过e.changedTouches[0].clientY获取触摸的位置
            }
            /**
             * 增加 e.preventDefault() 解决在做移动端下拉操作的时候,真机测试时会把整个网页都进行下拉,(微信端)可能会出现的 "此网页由xxx提供"的现象
             */
            e.preventDefault()
            /**
             * 下拉操作中也要添加e.stopPropagation()来阻止事件冒泡广播
            */
            e.stopPropagation()
        },
        // 触摸下拉事件结束后重置第一次Y轴偏移量和重置vuex里的offsetY
        moveEnd(e) {
            this.setOffsetY(0)
            this.firstOffsetY = null
        },
        // mask蒙层点击事件,当点击左边区域切换到上一页,点击右边区域切换到下一页,点击中间部分切换导航和菜单
        onMaskClick(e) {
            /** 
             * 在触发PC端鼠标下拉操作中,由于鼠标抬起一定会触发onMaskClick事件,因此通过mouseState状态来控制是否往下执行
             *   this.mouseState === 2 || this.mouseState === 3 表示此时是鼠标下拉操作,不是点击事件
             *  */
            if (this.mouseState && (this.mouseState === 2 || this.mouseState === 3)) {
                return
            }

            const offsetX = e.offsetX
            const width = window.innerWidth
            if(offsetX > 0 && offsetX < width * 0.3) {
                this.prevPage()
            } else if (offsetX > 0 && offsetX > width * 0.7) {
                this.nextPage()
            } else {
                this.toggleTitleAndMenu()
            }
        },
}

优质内容筛选与推荐>>
1、跳出$.each()循环
2、重新回顾 symfony 内容
3、JavaScript 数据类型
4、生成性能测试报告
5、适应多行长文本的Android TextView


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn