专栏首页那些年我们学过的前端移动端 局部dom实现滚动

移动端 局部dom实现滚动

移动端局部dom添加滑动事件

源码

/**
 * moveTopLimit: 移动过程中,随着手指的滑动 dom的偏移量
 * modifyTopLimit: 触发touchEnd的时候 我们需要进行吸顶这样的一个交互 设置吸顶的范围
 */
export default class TouchMove {
    constructor(params) {
        this.props = params;
        this.checkParams(params);
        this.startY = 0;
        this.moveEndY = 0;
        this.oldMoveY = 0;
        this.offsetSum = 0;
        this.curDistance = 0;
        this.init();
    }
    checkParams() {
        const objectKey = [
            'Dom',
            'slider',
        ];
        const baseTypeKey = [
            'moveTopLimit',
            'moveBottomLimit',
            'modifyTopLimit',
            'modifyBottomLimit',
        ];
        objectKey.forEach((item) => {
            if (!this.props[item]) {
                throw new Error(`${item}传参错误,请检查之后重试`);
            }
        });
        baseTypeKey.forEach((item) => {
            if (this.props[item] === undefined ||
                (Object.prototype.toString.call(this.props[item]) !== '[object Number]'
                    && Object.prototype.toString.call(this.props[item]) !== '[object String]')) {
                throw new Error(`${item}传参错误,请传入数字或者字符类型的数字`);
            }
        });
    }
    init() {
        this.Dom = this.props.Dom;
        this.slider = this.props.slider;
        this.moveTopLimit = parseInt(this.props.moveTopLimit, 10) || 0;
        this.moveBottomLimit = parseInt(this.props.moveBottomLimit, 10) || 0;
        this.modifyTopLimit = parseInt(this.props.modifyTopLimit, 10) || 0;
        this.modifyBottomLimit = parseInt(this.props.modifyBottomLimit, 10) || 0;
        this.addListenerWheel();
    }
    addListenerWheel() {
        this.Dom.addEventListener('touchstart', (e) => {
            this.touchStart(e);
        });
        this.Dom.addEventListener('touchmove', (e) => {
            this.touchMove(e);
        });
        this.Dom.addEventListener('touchend', (e) => {
            this.touchEnd(e);
        });
    }
    touchStart(event) {
        this.startY = parseInt(event.touches[0].clientY, 10);
        this.oldMoveY = this.startY;
    }
    touchMove(event) {
        // 当屏幕上有多个touch或者页面被缩放过 就不执行move操作
        if (event.targetTouches.length > 1 || (event.scale && event.scale !== 1)) return;
        event.preventDefault();
        this.moveY = event.touches[0].clientY;
        this.offset = (this.moveY - this.oldMoveY);
        // 获取dom当前滚动值
        this.getCurDistance();
        this.offsetSum = this.offset + this.curDistance;
        // 设置滑动范围
        if (this.offsetSum > 0) {
            this.offsetSum = Math.min(this.offsetSum, this.moveTopLimit);
        } else if (this.offsetSum < 0) {
            this.offsetSum = Math.max(this.offsetSum, this.moveBottomLimit);
        }
        this.oldMoveY = this.moveY;
        this.movePosition(this.offsetSum);
    }
    touchEnd(event) {
        this.moveEndY = parseInt(event.changedTouches[0].clientY, 10);
        this.offset = (this.moveEndY - this.startY);
        this.getCurDistance();
        this.offsetSum = this.offset + this.curDistance;
        this.movePosition(this.offsetSum, 'end');
        // 修正位置 回弹效果
        this.modifyPosition(this.offsetSum);
    }
    getCurDistance() {
        if (this.slider.style.transform) {
            this.curDistance = parseInt(
                this.slider.style.transform.split(',')[1], 10) || 0;
        } else {
            this.curDistance = parseInt(
                this.slider.style.webkitTransform.split(',')[1], 10) || 0;
        }
    }
    movePosition(distance) {
        this.slider.style.webkitTransform = `translate3d(0,${distance}px, 0)`;
        this.slider.style.transform = `translate3d(0,${distance}px, 0)`;
    }
    modifyPosition(distance) {
        if (distance > this.modifyTopLimit) {
            this.curDistance = this.modifyTopLimit;
            this.movePosition(this.modifyTopLimit);
        } else if (distance < this.modifyBottomLimit) {
            this.curDistance = this.modifyBottomLimit;
            this.movePosition(this.modifyBottomLimit);
        }
    }
}

如何使用

    const dom = getElementsByClassName('lose-lottery-content')[0];
            const slider = getElementsByClassName('lose-lottery-container')[0];
            const itemHeight = getElementsByClassName('lottery-item')[0].clientHeight;
            const bottomlimit =
        getElementsByClassName('lose-lottery-container')[0].clientHeight -
        getElementsByClassName('lose-lottery-content')[0].clientHeight;
            // eslint-disable-next-line no-new
            new TouchMove({
                Dom: dom,
                slider,
                moveTopLimit: itemHeight,
                moveBottomLimit: -(bottomlimit + itemHeight),
                modifyTopLimit: 0,
                modifyBottomLimit: -(bottomlimit + 20),
            });

参考链接

https://github.com/surmon-china/vue-awesome-swiper/issues/423

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 浅谈react 中的 this 指向

    https://react.docschina.org/docs/react-without-jsx.html

    念念不忘
  • react 创建组件以及组件通信

    关于React.createClass方法与class App extends Component方法的区别

    念念不忘
  • jsonForest

    念念不忘
  • Openlayers2卷帘功能的实现

    在WebGIS开发中,经常会有用户提需求,要实现卷帘功能,卷帘功能主要是实现两张图之间的对比。在前文中,讲到了openlayers3以及Arcgis for j...

    lzugis
  • 求超大文件上传方案( B/S )

    需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在500M内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以501M来进行限制...

    用户6892318
  • 手把手教你用原生JavaScript造轮子(2)——轮播图(更新:ES6版本)

    通过上一篇文章的学习,我们基本掌握了一个轮子的封装和开发流程。那么这次将带大家开发一个更有难度的项目——轮播图,希望能进一步加深大家对于面向对象插件开发的理解和...

    前端博客 : alili.tech
  • 确认过眼神,你是喜欢Stream的人

    摘要:在学习Node的过程中,Stream流是常用的东东,在了解怎么使用它的同时,我们应该要深入了解它的具体实现。今天的主要带大家来写一写可读流的具体实现,就过...

    用户2145235
  • 不再彷徨:完全弄懂JavaScript中的this(译文总结)

    JavaScript 中的’this‘是动态的,它在函数运行时被确定而非在函数声明时被确定。所有的函数都可以调用'this',这无关于该函数是否属于某个对象。关...

    前端博客 : alili.tech
  • 从0到1,开发一个动画库(2)

    上一节讲到了最基础的内容,为动画构建“帧-值”对应的函数关系,完成“由帧到值”的计算过程。这一节将在上节代码的基础上谈谈如何给一个完整的动画添加各类事件。

    前端博客 : alili.tech
  • VUE+WebPack游戏设计:欲望都市城市图层的设计

    望月从良

扫码关注云+社区

领取腾讯云代金券