20230620----重返学习-移动端事件处理-响应式

day-095-ninety-five-20230620-移动端事件处理-响应式

移动端事件处理

移动端的事件处理

  • 移动端事件处理
    • PC端主要以:鼠标事件键盘事件资源加载事件动画事件等事件为主。
      • 其中clickPC端点击事件
    • 移动端主要以:手指事件单手指多手指)、资源加载事件动画事件等为主。
      • 其中,click移动端单击事件

移动端事件问题

  • 移动端事件的各个问题:
    • 问题1:click事件移动端存在300ms的延迟

      • 原因:
        • click事件移动端单击事件:
          • 在第一次点击后,需要观察300ms,看是否触发了第二次点击;
            • 如果没有触发第二次点击,则为单击操作,触发click事件
            • 如果触发了第二次点击,则为双击操作click事件是不触发的!
      • 解决方案:
        1. touch事件模型-即单手指事件模型,来代替click事件

          • touchstart:手指开始触摸。

          • touchmove:手指移动。

          • touchend:手指离开。

            DOCTYPE html>
            <html>
              <head>
                <meta charset="UTF-8" />
                <meta name="viewport" content="width=device-width, initial-scale=1.0" />
                <title>基于touch实现点击操作title>
                <style>
                  .box {
                    position: absolute;
                    top: 20px;
                    left: 40px;
                    box-sizing: border-box;
                    width: 100px;
                    height: 100px;
                    border: 1px solid #000;
                  }
                style>
              head>
            
              <body>
                <div class="box">div>
            
                
                <script>
                  // 基于touch事件模型模拟出“点击”的效果
                  const box = document.querySelector(".box");
            
                  // 简易的处理方法:只要手指离开盒子,则认为触发了点击操作「这样是不准确的,如果手指之前发了移动,则本操作不再是点击,而是滑动」
                  box.ontouchend = function () {
                    this.style.background = "pink";
                  };
                script>
              body>
            html>
            
          • touchcancel:因意外情况如手机没电,导致touch事件取消了。

          • 但是这种方式,如果需要自己去实现,太繁琐了!

            DOCTYPE html>
            <html>
              <head>
                <meta charset="UTF-8" />
                <meta name="viewport" content="width=device-width, initial-scale=1.0" />
                <title>基于touch实现点击操作title>
                <style>
                  .box {
                    position: absolute;
                    top: 20px;
                    left: 40px;
                    box-sizing: border-box;
                    width: 100px;
                    height: 100px;
                    border: 1px solid #000;
                  }
                style>
              head>
            
              <body>
                <div class="box">div>
            
                
                <script>
                  // 基于touch事件模型模拟出“点击”的效果
                  const box = document.querySelector(".box");
                  box.ontouchstart = function (ev) {
                    /*
                        手指按下的时候:记录手指起始的坐标位置
                        ev:TouchEvent
                          touches/targetTouches/changedTouches:都记录了手指位置的相关信息「伪数组」
                          我们平时都用changedTouches,因为其可以在 touchend 事件中,记录出手指离开屏幕时的坐标
                        */
                    let finger = ev.changedTouches[0];
                    this.startX = finger.pageX;
                    this.startY = finger.pageY;
                    this.isMove = false;
                  };
                  box.ontouchmove = function (ev) {
                    /*
                        手指移动的时候:获取最新的手指坐标,减去起始坐标,计算出偏移的距离
                        在给定的误差值(一般都是10px)范围内,计算是否发生移动
                        */
                    let finger = ev.changedTouches[0];
                    let changeX = finger.pageX - this.startX,
                      changeY = finger.pageY - this.startY;
                    if (Math.abs(changeX) > 10 || Math.abs(changeY) > 10)
                      this.isMove = true;
                    this.changeX = changeX;
                    this.changeY = changeY;
                  };
                  box.ontouchend = function (ev) {
                    /*
                        手指离开屏幕的时候:判断是移动还是点击操作
                        如果是移动操作,还可以基于偏移的距离算出移动的方向
                        */
                    let { isMove, changeX, changeY } = this;
                    if (!isMove) {
                      console.log("当前是点击操作");
                      this.style.background = "pink";
                      return;
                    }
                    if (Math.abs(changeX) >= Math.abs(changeY)) {
                      // 是左右滑动
                      if (changeX >= 0) {
                        console.log("向右滑动");
                      } else {
                        console.log("向左滑动");
                      }
                      return;
                    }
                    // 是上下滑动
                    if (changeY >= 0) {
                      console.log("向下滑动");
                    } else {
                      console.log("向上滑动");
                    }
                  };
            
                  /*
                    移动端的常规操作,基本上都是基于 touchstart/touchmove/touchend 模拟出来的
                      + 模拟点击
                      + 模拟滑动「知道滑动方向」
                      + 模拟单击/双击「300ms」
                      + 模拟长按「750ms」
                      + ...
                    对于一些需要多根手指进行的操作,可以基于 gesturestart/gesturechange/gestureend 模拟出来
                      + 缩放
                      + 旋转
                      + ...
                    */
                script>
              body>
            html>
            
        2. 基于一些现有的封装好的事件库来解决。

          • fastclick.js 只能解决click事件300ms延迟问题。

            • 适用于:操作简单的移动端产品上,在此产品上,只有点击行为,此时我们继续使用click事件,只不过基于fastclick插件,把其300ms延迟处理掉即可!
            • 原理:基于事件委托,对页面中的click行为统一的处理,核心还是基于touch事件模型解决的!
            • 代码:
              • JS高级进阶/day0619_QQMusic/js/fastclick.js

              • JS高级进阶/day0619_QQMusic/touchDemo.html

                DOCTYPE html>
                <html>
                  <head>
                    <meta charset="UTF-8" />
                    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
                    <title>基于touch实现点击操作title>
                    <style>
                      .box {
                        position: absolute;
                        top: 20px;
                        left: 40px;
                        box-sizing: border-box;
                        width: 100px;
                        height: 100px;
                        border: 1px solid #000;
                      }
                    style>
                  head>
                
                  <body>
                    <div class="box">div>
                
                    <script src="js/fastclick.js">script>
                    <script>
                      // 这样的处理在移动端会有300ms延迟问题
                      // 此时我们基于 fastclick 插件处理一下即可
                      FastClick.attach(document.body);
                      const box = document.querySelector(".box");
                      box.onclick = function () {
                        console.log(`fastclick`);
                        this.style.background = "pink";
                      };
                    script>
                  body>
                html>
                
          • Zepto.js 被称为移动端的jQuery库,语法和jQuery非常类似,但是能够更好的支持移动端。

            • 相比较于jQuery来讲:
              • 不考虑IE8IE8以下版本兼容
              • 只实现了jQuery最常用最核心方法
                • 导致ZeptojQuery库小很多。
              • 支持css3动画
              • 封装了一套完善的移动端事件处理方案
            • 支持的移动端事件操作。
              • tap 点击。
              • singleTap 单击。
              • doubleTap 双击。
              • longTap 长按。
              • swipeswipeLeft/swipeRight/swipeDown/swipeUp 滑动。
              • pinchIn/pinchOut 缩放。
            • 但是ZeptojQuery一样,其大部分代码是用来操作DOM的,已经不适用于当下的Vue开发/React开发了。
            • 代码:
              • JS高级进阶/day0619_QQMusic/js/zepto.min.js

              • JS高级进阶/day0619_QQMusic/touchDemo.html

                DOCTYPE html>
                <html>
                  <head>
                    <meta charset="UTF-8" />
                    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
                    <title>基于touch实现点击操作title>
                    <style>
                      .box {
                        position: absolute;
                        top: 20px;
                        left: 40px;
                        box-sizing: border-box;
                        width: 100px;
                        height: 100px;
                        border: 1px solid #000;
                      }
                    style>
                  head>
                
                  <body>
                    <div class="box">div>
                
                    <script src="js/zepto.min.js">script>
                    <script>
                      $(".box").tap(function () {
                        console.log(`zepto-tap`);
                
                        $(this).css({
                          background: "pink",
                        });
                      });
                    script>
                  body>
                html>
                
          • hammer.js 移动端专属的事件库

            • hammer.js
            • 代码:
              • JS高级进阶/day0619_QQMusic/js/hammer.min.js

              • JS高级进阶/day0619_QQMusic/touchDemo.html

                DOCTYPE html>
                <html>
                  <head>
                    <meta charset="UTF-8" />
                    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
                    <title>基于touch实现点击操作title>
                    <style>
                      .box {
                        position: absolute;
                        top: 20px;
                        left: 40px;
                        box-sizing: border-box;
                        width: 100px;
                        height: 100px;
                        border: 1px solid #000;
                      }
                    style>
                  head>
                
                  <body>
                    <div class="box">div>
                
                    <script src="js/hammer.min.js">script>
                    <script>
                      const box = document.querySelector(".box");
                      const instHammer = new Hammer(box);
                      instHammer.on("tap", function () {
                        console.log(`hammer-tap`);
                        box.style.background = "pink";
                      });
                    script>
                  body>
                html>
                
    • 问题2:事件穿透问题

      • 事件传透的是指:触发某个目标元素的触摸事件(touch事件)时,会同时触发该目标元素相同位置中其他元素鼠标点击click事件
        • 触发步骤:
          1. 触摸第一层,让第一层隐藏。
          2. 露出第二层,而第二层是基于click事件处理的!
      • 事件触发的先后顺序是:
      • 解决方案:click和touch事件不要混合在一起使用!!
    • 问题3:keydown/up/press等事件在移动端用不了,统一基于input事件代替即可!

      • 文本框.οninput=function(){}
      • 只要文本框中有内容的输入,则input事件就会触发!

移动端模拟点击操作

没做处理-直接用click代替

DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>基于touch实现点击操作title>
    <style>
      .box {
        position: absolute;
        top: 20px;
        left: 40px;
        box-sizing: border-box;
        width: 100px;
        height: 100px;
        border: 1px solid #ccc;
      }
    style>
  head>
  <body>
    <div class="box">div>
  body>
html>

<script>
  const box = document.querySelector(".box");
  // 这样的处理在移动端会有300ms延迟问题。
  box.onclick = function () {
    this.style.background = "pink";
  };
script>

简易的处理方法-直接用touchend代替

DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>基于touch实现点击操作title>
    <style>
      .box {
        position: absolute;
        top: 20px;
        left: 40px;
        box-sizing: border-box;
        width: 100px;
        height: 100px;
        border: 1px solid #ccc;
      }
    style>
  head>
  <body>
    <div class="box">div>
  body>
html>

<script>
  // 基于touch事件模型模拟出点击的效果。
  const box = document.querySelector(".box");
  // 简易的处理方法:只要手指离开盒子,则认为触发了点击操作。
  // 这样是不准确的,如果手指之前发生了移动,则本操作不再是点击,而是滑动。
  box.ontouchend = function () {
    console.log(`touchend-->`);
    this.style.background = "pink";
  };
script>

用touch事件模型来代替click事件

  • 思路:
    • 手指按下的时候:记录手指起始的坐标位置。
      • ev:TouchEvent
        • touches/targetTouches/changedTouches:都记录了手指位置的相关信息,结果是一个伪数组。
          • 我们平时都用changedTouches,因为其可以在touchend事件中,记录出手指离开屏幕时的坐标。
    • 手指移动的时候:获取最新的手指坐标,减去起始坐标,计算出偏移的距离。
      • 在给定的误差值(一般都是10px)范围内,计算是否发生移动。
    • 手指离开屏幕的时候:判断是移动还是点击操作。
      • 如果是移动操作,还可以基于偏移的距离算出移动的方向。
    • 移动端的事件
      • 移动端的常规操作,基本上都是基于touchstart/touchmove/touchend模拟出来的。
        • 模拟点击。
        • 模拟滑动-知道滑动方向。
        • 模拟单击/双击-300ms。
        • 模拟长按-750ms。
      • 对于一些需要多根手指进行的操作,可以基于gesturestart/gesturechange/gestureend模拟出来。
        • 缩放。
        • 旋转。
DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>基于touch实现点击操作title>
    <style>
      .box {
        position: absolute;
        top: 20px;
        left: 40px;
        box-sizing: border-box;
        width: 100px;
        height: 100px;
        border: 1px solid #ccc;
      }
    style>
  head>
  <body>
    <div class="box">div>
  body>
html>

<script>
  // 基于touch事件模型模拟出点击的效果。
  const box = document.querySelector(".box");
  box.ontouchstart = function (ev) {
    // 手指按下的时候:记录手指起始的坐标位置。
    // ev:TouchEvent
    //   - touches/targetTouches/changedTouches:都记录了手指位置的相关信息,结果是一个伪数组。
    //     - 我们平时都用changedTouches,因为其可以在touchend事件中,记录出手指离开屏幕时的坐标。

    // console.log(`ev-->`, ev);
    let finger = ev.changedTouches[0];
    // console.log(`finger-->`, finger);
    this.startX = finger.pageX;
    this.startY = finger.pageY;
    this.isMove = false;
  };
  box.ontouchmove = function (ev) {
    // 手指移动的时候:获取最新的手指坐标,减去起始坐标,计算出偏移的距离。
    // 在给定的误差值(一般都是10px)范围内,计算是否发生移动。

    let finger = ev.changedTouches[0];
    // console.log(`finger-->`, finger);
    let changeX = finger.pageX - this.startX;
    let changeY = finger.pageY - this.startY;
    if (Math.abs(changeX) > 10 || Math.abs(changeY) > 10) {
      this.isMove = true;
    }
    this.changeX = changeX;
    this.changeY = changeY;
  };
  box.ontouchend = function (ev) {
    // 手指离开屏幕的时候:判断是移动还是点击操作。
    // 如果是移动操作,还可以基于偏移的距离算出移动的方向。
    let { isMove, changeX, changeY } = this;
    if (!isMove) {
      console.log(`当前是点击操作`);
      this.style.background = "pink";
      return;
    }
    if (Math.abs(changeX) >= Math.abs(changeY)) {
      // 是左右滑动。
      if (changeX >= 0) {
        console.log(`向右滑动`);
      } else {
        console.log(`向左滑动`);
      }
      return
    }

    // 是上下滑动。
    if (changeY >= 0) {
      console.log(`向下滑动`);
    } else {
      console.log(`向上滑动`);
    }
  };
  // - 移动端的常规操作,基本上都是基于touchstart/touchmove/touchend模拟出来的。
  //   - 模拟点击。
  //   - 模拟滑动-知道滑动方向。
  //   - 模拟单击/双击-300ms。
  //   - 模拟长按-750ms。
  //   - ...
  // - 对于一些需要多根手指进行的操作,可以基于gesturestart/gesturechange/gestureend模拟出来。
  //   - 缩放。
  //   - 旋转。
  //   - ...
script>

基于fastclick插件处理

基于zepto进行处理

基于hammer进行处理

响应式

响应式布局开发技巧

  • 需要做响应式:
    1. PC端全屏项目(一般都是管理系统)
      • 技术方案:外层容器的宽高采用百分比布局-如vw与vh,一些具体的元素基本都是固定布局。偶尔基于@media进行微调。
    2. PC端和移动端共用一套项目(一般是结构和样式较为简单的企业官网/宣传页等)
      • 技术方案:流式布局(外层容器的宽度按照百分比方式处理),基于@media进行结构和样式的调整。

        @media all and (max-width:960px) {
          .header{
            //...
          }
          ...
        }
        
        • 基于@media调整样式越细,展示效果会越好!
        • 核心就是大量写样式。
    3. 移动端项目(适配不同型号的手机设备,有的还需要适配pad端)
      • 传统方案:基于@media进行样式调整,尽可能适配更多的设备,这是官方提供的方案。
        • 这也是官方唯一认可方案:@media。
      • 发展:
        1. 固定布局:只写最小的尺寸,如320px,中间居中。
        2. 2023年目前:rem等比缩放。
      • 新方案:rem等比缩放。
      • 不论那一种方案,目前做排列布局,基本上都是基于flex来处理!

rem响应式布局方案

  • 移动端响应式布局第一步:设置meta标签的viewport。

    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    
    • viewport:设置视口(或html页面)的规则。
      • width=device-width 让HTML渲染的宽度和设备宽度保持一致。
      • initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0 不让HTML页面进行缩放。
        • maximum-scale=1.0, minimum-scale=1.0 是为了兼容安卓低端机。
      • user-scalable=no 禁止手动缩放。
    • 如果不设置meta标签的viewport会出现什么问题?
      • 不论手机设备多宽,HTML页面都是以980px的宽度进行渲染。这样就会出现,手机屏幕渲染不全的情况。
        • 不完全渲染:就会出现横竖向的滚动条。
        • 完全渲染:就要把页面整体缩小,所有内容都会变得很小。
  • rem响应式布局方案

    1. 什么是rem?
      • px物理像素,固定单位。

      • em相对单位,相对于父元素的字体大小。

        • 一般用于段落首行缩进两个汉字之类的效果。

          .box{
            font-size:14px;//此时在该元素的子元素中1em=14px;
            p{
              text-indent:2em;//首行缩进两个字符。
            }
          }
          
      • rem(root em) 相对单位,相对于根元素(也就是html)的字体大小。

        html{
          font-size:20px;//1rem=20px。浏览器能识别的最小字体是12px。
        }
        .box1{
          width:100px;
        }
        .box2{
          width:5rem;
        }
        //目前box1和box2是一样大的。
        //但是如果以后,把html的字体改为30px了,那么box1依然是100px,但是box2则自动变为150px了!
        //也就是:只要修改根元素的字体大小,那么所有以rem为单位的样式,都会自动跟着等比缩放。
        
        • 也就是:只要修改根元素的字体大小,那么所有以rem为单位的样式,都会自动跟着等比缩放。
    2. 基于rem实现响应式布局开发的步骤:
      • 第一步:按照特定的尺寸(一般是设计稿的尺寸),设置rem和px的初始转换比例,然后把测量出来的像素值,全部按照这个比例,改为rem值,赋值给元素的样式!

        • 设计稿的尺寸:一般都是750px的。

          • 但UI组件库的设计稿一般都是375px的。
        • rem和px的初始转换比例:设置的值一定是方便计算的!

          html{
            font-size:16px;//1rem=100px ; 750px
          }
          

          量出来一个盒子大小是300px*260px。font-size为28px。

          .box{
            width:3rem;
            height:2.6rem;
            font-size:0.28rem;
          }
          
      • 第二步:获取当前设备的尺寸,计算出相比较于设计稿而言,缩放的比例。然后按照这个比例,去修改html的字体大小(也就是rem和px的换算比例)。

        • 公式:当前设备的宽度/当前的换算比例=设计稿宽度(750px)/初始换算比例(100)
          • 当前的换算比例=(当前设备的宽度/设计稿宽度(750px))*初始换算比例(100)
        • 基于公式计算出最新的换算比例后,修改html的字体大小,那么之前所有以rem为单位的样式,都会按照最新的换算比例,实现等比缩放。
      • 第三步:我们一般都会限制一个最大的缩放范围(比如:540),设备宽度即便超过这个范围,换算比例也不会再继续放大了,整个页面内容最宽540,左右两边预留空白即可。

        • 为什么设计师给我们的设计稿,都比实际的手机尺寸大一倍?
          • iphone6/7/8 -> 375px
          • iphone6/7/8 plus / iphoneXR -> 414px
        • 750px的设计稿是参照375px设备来设计的,之所以大一倍,是因为:DPR屏幕像素密度比Device Pixel Ratio
          • 物理像素
          • 分辨率
        • 在DPR=2.0的设备上,我们准备的原始图片大小,要比最后设置的尺寸大一倍。
          • 屏幕就是按照大一倍的方式渲染的。
        • 在DPR=3.0的上,原始图片大小,要比设置的尺寸大两倍。
        • DPR对图片是最有影响的,对于文字等影响不大!!而且经过实测,DPR=3.0相比于DPR=2.0,变化也不是很大!
        • 所以设计师给我们比真正尺寸大一倍的设计稿,其目的:让我们切出比设计尺寸大一倍的图片!如果设计稿中没有图片,按照375px的设计稿也是没有问题的。UI组件库一般都是这样的!
        • 理论上,官方告诉我们图片的处理方案是这样的:
        • 只不过前端这样处理太麻烦了,需要写js代码或@media动态控制加载的图片,而NativeApp开发有现成的处理方案。
          • 都是按照三张图处理。
        • 所以在WebApp开发中,我们只会准备一张二倍图,不论DPR是多少,加载的都是这个二倍图。
          • 如果某些二倍图片在DPR为3的设备上,看越来模糊,就单独找设计师要一张三倍图。
          • 目前实测,一般用二倍图就好了!

移动端处理css

  • 在移动端编写CSS3样式,为了兼容低版本的浏览器,我们需要写两套
    • -webkit-transition:
    • transition:
  • 期望可以自动加前缀
    1. webpack -> postcss

      • 需要使用webpack。
    2. prefixfree.min.js

      • 可以通过引入这个js来就可以了。
      <script src="./js/prefixfree.min.js" async>script>
      

参考

你可能感兴趣的:(重返学习,原生js学习,html,学习,css,css3)