web中的移动端的Touch事件和手动实现侧边栏

web.jpeg

Touch事件

  • 只针对移动端使用, 不支持PC端
  • 主要有三个事件
    • touchstart手指触碰屏幕的时候触发
    • touchmove手指移动的时候触发
    • touchend 手指离开的时候
 let oDiv = document.querySelector("div");

    oDiv.addEventListener("touchstart",function () {

        console.log("开始触摸");
    });

    oDiv.addEventListener("touchmove",function () {

        console.log("移动一手指");
    });

    oDiv.addEventListener("touchend",function () {

        console.log("结束触摸---")
    });

Touch事件对象

  • 我们知道PC端每一个处理事件都有一个事件对象,Touch事件也是
 let oDiv = document.querySelector("div");
    oDiv.addEventListener("touchstart",function (e) {
        e = e || window.event;
        console.log(e);
    })
image.png

我们经常使用的就是 touches,targetToucheschangedTouches
touches:页面上(屏幕)所有的触目点
targetTouches:元素(容器盒子)上的触摸点,当touchend执行的时候,event事件里面的 targetTouches不在有触摸点对象
changedTouches:当前屏幕上刚刚接触的手指或者离开的手指
区别:
touches和targetTouches
1.如果都是将手指按到了同一个元素上, 那么这两个对象中保存的内容是一样的
2.如果是将手指按到了不同的元素上, 那么这个两个对象中保存的内容不一样
3.touches保存的是所有元素中的手指, 而targetTouches保存的是当前元素中的手指

Touch事件对象中的clientX,pageX,screenX

  • screenX/screenY是相对于屏幕左上角的偏移位
  • clientX/clientY是相对于可视区域左上角的偏移位
  • pageX/pageY是相对于内容左上角的偏移位(内容区域有可能超出屏幕)
  <style>
        *{
            padding: 0;
            margin: 0;
        }

        div{
            width: 600px;
            height: 100px;
            background: linear-gradient(to right, red, green);
            margin-left: 50px;
            margin-top: 50px;
        }

    </style>


<script>
  
    let oDiv = document.querySelector("div");

    oDiv.addEventListener("touchstart",function (event) {

        event = event || window.event;

        console.log(event.targetTouches);
        let obj = event.targetTouches[0];
        console.log( "clientX:"+ obj.clientX,"clientY:"+obj.clientY);
        console.log("pageX:"+obj.pageX,"pageY:"+obj.pageY );
        console.log("screenX:"+obj.screenX,"screenX:"+obj.screenY );

        /*
        screenX:是参照 页面/屏幕 左上角的
        clientX:参考点是 可视区域的 左上角
        pageX: 是参考 内容的左上角 (内容过宽 超出屏幕)
         */

        /*


    });

</script>


下图 可以更改的解释clientX,pageX,screenX
1.红色代表screenX
2.黄色代表pageX,蓝色的长方格是 内容区域的超出了手机屏幕
3.手绘的蓝色是clientX
也可以参考JS操作html元素中clientX、offsetX、screenX、pageX的区别一文的概述

image.png

Touch事件的点透问题

  • 当一个元素放覆盖了另一个元素, 覆盖的元素监听touch事件,而下面的元素监听click事件,并且touch事件触发后覆盖的元素就消失了, 那么就会出现点透问题

注意粉色盒子消失,log的打印情况

点透问题.gif
<script type="text/javascript">

    // 绿色盒子 和  粉色盒子 是兄弟关系
    
    let oBox = document.querySelector(".box");
    let oTap = document.querySelector(".tap");

    //绿色盒子
    oBox.addEventListener("click",function () {
        console.log("-------");
    });

    //粉色盒子
    oTap.addEventListener("touchstart",function () {
        oTap.style.display = "none";
    });

</script>

需要提醒的是:这种情况不是 事件冒泡,因为2个盒子是兄弟关系,不是父子关系

出现这种情况的原因是什么呢?
原因是

1.当我们手指触摸屏幕的时候,系统会生成2个事件,一个是touch事件,一个是click事件, touch事件优先click事件执行, click事件相对会延迟 100-300毫秒

2.当touch事件执行的时候pink粉色盒子的display属性更改为none粉色盒子消失,而click事件在200毫秒之后,执行的时候,发现粉色盒子已经消失,那么click事件就会执行 对应的触摸点位置的box盒子,进而触发box盒子的click事件

如何解决?

这个解决其实就是 阻止事件扩散其实就是阻止默认事件的执行 event.preventDefault(),所以需要在 粉色盒子执行touch 和 click事件时加上

 //粉色盒子
    oTap.addEventListener("touchstart",function (event) {
        event = event || window.event;
        oTap.style.display = "none";
        //阻止事件的默认行为
        event.preventDefault();
    });

其他的一些解决方法 第三方插件 比如:Fastclick专门用来解决这个问题,Zepto插件,注意早期的Zepto没有处理这个点透问题

关于 移动端点击事件的封装

点击事件的特点
1.按下和离开时间不能太久 100 - 200ms
2.按下和离开距离不能(不能移动)太远 5px
3.单根手指

 function Tap(dom, fn) {
        if(!(dom instanceof HTMLElement)){
            throw new Error("请传入一个DOM元素");
        }
        let startX = 0;
        let startY = 0;
        let startTime = 0;
        dom.ontouchstart = function (event) {
            // 1.判断当前元素中有几根手指
            if(event.targetTouches.length > 1){
                return;
            }
            // 2.拿到手指按下的位置
            startX = event.targetTouches[0].clientX;
            startY = event.targetTouches[0].clientY;
            // 3.拿到手指按下的时间
            startTime = Date.now();
        }
        dom.ontouchend = function (event) {
            // 1.判断有几根手指离开了
            if(event.changedTouches.length > 1){
                return;
            }
            // 2.拿到离开手指的位置
            let endX = event.changedTouches[0].clientX;
            let endY = event.changedTouches[0].clientY;
            // 3.判断手指离开的位置和按下位置的距离
            if(Math.abs(endX - startX) > 5 ||
                Math.abs(endY - startY) > 5){
                return;
            }
            // 4.拿到手指离开的时间
            let endTime = Date.now();
            // 5.判断手指离开的时间和按下的时间
            if(endTime - startTime > 100){
                return;
            }
            // console.log("单击事件");
            fn && fn();
        }
    }
  • 另外的一种方式
//封装 tap事件
    function tap(element,callBack) {
        //记录刚开始的触摸时间
        let startTime = null;
        //记录结束的时间
        let endTime = null;
        //是否移动的标志
        let isMove = false;

        //触摸开始
        element.addEventListener("touchstart",function (e) {
            //获取当前的时间戳
            startTime = Date.now();
        });

        //移动
        element.addEventListener("touchmove",function (e) {
            //移动了
            isMove = true;
        });

        //结束
        element.addEventListener("touchend",function (e) {
            //获取结束的时间戳
            endTime = Date.now();

            if (endTime - startTime <= 200 && isMove === false){
                if (callBack){
                    //触摸对象返回给 回调函数
                    callBack(e);
                }

            }
            // 还原初始状态
            isMove = false;
        });

    }


手动实现侧边栏

  • 三层结构组成:有一个父级盒子Div包括一个子级盒子ul,ul移动,ul里面包括你的内容

原理:1.手指触摸屏幕 开始startY 记录位置 2.手指移动记录位置endy,其结束的偏移量offsetY = endY - startY 需要注意的是: 因为你第一次和 第二次 offsetY值不同,需要一个记录变量currentY保存上次的offsetY,这样在下次移动的时候,就是在上一次的基础上 滚动

<style>
        *{
            padding: 0;
            margin: 0;
            touch-action: none;
        }
        html,body{
            width: 100%;
            height: 100%;
        }
        ul {
            list-style: none;
        }
        a{
            text-decoration: none;
        }
        .box{
            display: inline-block;
            width: 95px;
            border: 1px solid;
            position: relative;
            overflow: hidden;
            /*高度100% 就是手机屏幕的 高度*/
            /*不设置的话 ul撑开div 高度和ul的一样了*/
            height: 100%;

        }
        .box > ul {
            width: 100%;
            position: relative;
        }
        .box > ul > li {
            height: 44px;
            line-height: 44px;
            width: 100%;
            border-bottom: 1px solid;
            text-align: center;
        }


    </style>
image.png
  • 实现
<script type="text/javascript">

    let oDiv = document.querySelector(".box");
    let oUl = document.querySelector("ul");

    console.log(oDiv.offsetHeight,oUl.offsetHeight);

    let startY = 0;
    //移动的位置
    let offsetY = 0;
    //保存上一次移动的位置
    let currentY = 0;
    //定义的缓冲量
    let buffer = 100;

    let maxOffsetY = 0;
    //向上移动 Y值是 负数
    let minOffsetY = - (oUl.offsetHeight - oDiv.offsetHeight);

    console.log("minOffsetY:",minOffsetY);

    oUl.addEventListener("touchstart",function (e) {
        //获取开始的位置
        startY = e.targetTouches[0].clientY;

    });

    //移动
    oUl.addEventListener("touchmove",function (e) {
        let endY = e.targetTouches[0].clientY;
        offsetY = endY - startY;
        //当上一次currentY的便宜 + 现在的offsetY 偏移量 > 极限缓冲的时候 不能在向下移动
        if ((currentY + offsetY) >= (maxOffsetY + buffer)){
            return;
        }
        if ((currentY + offsetY) <= (minOffsetY - buffer)){
            return;
        }


        this.style.top = currentY + offsetY + "px";

    });

    //触摸结束
    oUl.addEventListener("touchend",function (e) {
        //当手指 离开 屏幕的时候 记录 上一次 移动的位置
        currentY += offsetY;
        //当向下移动的距离 大于等于 最大的极限值时
        if (currentY >= maxOffsetY){
            currentY = maxOffsetY;
            //复位
            // this.style.top = currentY + "px";
        } else if (currentY < minOffsetY ){
            currentY = minOffsetY;
            //复位
            // this.style.top = currentY + "px";
        }

        console.log(currentY,minOffsetY);

        //复位
        this.style.top = currentY + "px";

    });

</script>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  •   JavaScript 与 HTML 之间的交互是通过事件实现的。   事件,就是文档或浏览器窗口中发生的一些特...
    霜天晓阅读 3,426评论 1 11
  • 一、 基础事件 1.click事件 单击事件,类似于PC端的click,但在移动端中,连续click的触发有200...
    满天繁星_28c5阅读 600评论 0 0
  • 本节介绍各种常见的浏览器事件。 鼠标事件 鼠标事件指与鼠标相关的事件,主要有以下一些。 click 事件,dblc...
    许先生__阅读 2,284评论 0 4
  • 在前端的移动Web开发中,有一部分事件只在移动端产生,如触摸相关的事件。接下来给大家简单总结一下移动端的事件。 1...
    IT老马阅读 4,984评论 1 20
  • Web 浏览器中可能发生的事件有很多类型。如前所述,不同的事件类型具有不同的信息,而 DOM3 级事件规定了以下几...
    More_5897阅读 823评论 1 0