通过touch事件手写实现页面在移动端的触屏滚动功能

本文介绍了一种利用touch事件在触屏上实现页面滚动的方法,适用于移动端和集成Chromium内核的客户端应用。通过监听touchstart、touchmove、touchend等事件,并计算接触点的移动偏移量来实现页面的滚动。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文主要利用touch事件,实现了在触屏上的触摸滚动页面功能,类似手机浏览器上原生的触屏滚动事件。

目前在PC和移动端的浏览器环境中,在有原生的鼠标滚轮滚动和触屏滚动功能的情况下,这个功能的使用场景应该是极其有限的。

写这个小功能的起因是:上周临时接手一个集成了chromium内核的客户端CS项目,完成demo后部署到surface上,鼠标滚轮滚动页面效果正常,但触屏不能滚动页面,于是手写一组touch事件做测试。

本文包括下边三部分:

  • touch事件
  • 各种x,y
  • 功能实现

    1. touch事件

    touch事件组(我取的名字),实际上是Touch对象的Event属性,包括了touchstarttouchmovetouchendtouchcancel四个事件:

    • touchstart 事件:手指(或触摸笔一类的设备)与触屏设备表面接触时触发;
    • touchend事件:手指离开触屏设备表面时触发;
    • touchmove事件:手指在触屏设备表面移动时触发;
    • touchcancel 事件:当接触点被某些方式打乱时触发 (例如双指/多指操作等,本文不涉及touchcancel事件)。

    实现这个功能的主要思路就是:在touchstart 事件中记录DOM元素和接触点的初始位置;在touchmove事件中记录接触点的当前位置,根据以上记录的信息计算出接触点移动前后的xy方向的偏移量,最后利用这个偏移量对DOM元素进行重新定位。

在上代码前,先复习一下 DOM 事件涉及的各种 xy

2. 各种 xy
  • clientXclientY :事件接触点相对于窗口的XY坐标。例如窗口初始状态时点击页面的左上角,这时对应的值为event.clientX = 0event.clientY = 0;页面纵向滚动100px,这时再点击页面左上角仍然得到(0,0),而上次点击的接触点已经是(0,-100)了。
  • pageXpageY :事件接触点相对于HTML文档的XY坐标。在窗口初始状态,这两个值与clientXclientY 是相同的,区别在于当窗口发生滚动时。如上例的事件,第一次事件的pageXpageY 值同样为(0,0),而第二次事件中窗口左上角pageXpageY 的值则是(0,100)。
  • screenXscreenY :事件接触点相对于显示器边沿的XY坐标。嗯,应该已经很好理解了吧。
  • layerXlayerY:事件接触点相对于positionabsoluterelative的父元素外边缘的距离(如果最近的一级父元素没有相应的position值,则继续往上级对应),这个外边缘指的是boder的最外沿,至于paddingbodermargin的位置这里就不复习了。
  • offsetXoffsetY:事件接触点相对于触发事件元素的左上角的偏移,这两个值在不同浏览器的表现有一些区别,使用的时候需要注意,比如在chromeopera,、safari中是指外边缘,即把从边框的外边沿起算,firefoxie中则从边框的内边沿起算。
  • 另外还有xy等一些不同浏览器支持不足的属性,不再一一复习。

    本例中每次触摸滑动时需要计算接触点在屏幕上的偏移量,因为移动端一般是固定窗口,这里我们又只计算相对位置,因此具体使用的属性可以有多个选择,实际开发中使用的是pageY(纵向滚动)。

上代码前最后需要注意一点,就是当已经滚动到顶部和底部的时候,一定要及时提醒它悬崖勒马啊!(误)

3. 功能实现
// 获取要滚动的元素对象
var infoObj = document.getElementById("content-info-body");
infoObj.addEventListener("touchstart", function (event) {
    event.preventDefault();
    // 获取该元素相对于父级元素的top值(父级元素需要有position,当前元素position:relative)
    var startTop = this.offsetTop;
    //touches是屏幕上所有的touch,取第一个
    var touchstart = event.targetTouches[0]; 
    //取触点的初始
    startPos = {
        x: touchstart.pageX,
        y: touchstart.pageY,
    }; 

    infoObj.addEventListener('touchmove', function (event) {
        // 这句视情况而定,是为了屏蔽原生的touch滚动事件,而我的项目里没有这个,尴尬
        event.preventDefault();
        var touchmove = event.targetTouches[0];  
        // 偏移量
        var offsetPos = {
            x: touchmove.pageX - startPos.x,
            y: touchmove.pageY - startPos.y
        };  
        // 重新定位需要的目标top值
        var endTop = startTop + offsetPos.y;
        // 需要判断滚动到顶和到底的情况
        if (endTop < 10 && endTop > this.parentElement.offsetHeight - this.offsetHeight) {
            this.style.top = endTop + 'px';
        } else if (endTop >= 10) {
            this.style.top = '0px';
        } else {
            // this.style.top = '-536px';
            this.style.top = (this.parentElement.offsetHeight - this.offsetHeight - 10) + 'px';
        }
    });  
    infoObj.addEventListener('touchend', function (event) {  
        infoObj.removeEventListener('touchmove', this, false);  
        infoObj.removeEventListener('touchend', this, false);
    });
})

到此这个功能就实现了,在手机上测试良好,在这个基础上可以优化一下,在touchend里加一个小的后续偏移,这样就很接近原生的表现了。

说一千道一万,这个功能最后还是没有用到,这涉及C#JS交互的cefsharp的某些设置问题,在这里就不讨论了,借这个机会加深一下对DOM事件的理解,也是一个不错的过程。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值