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

news/2024/11/15 7:30:53/

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><!-- IMPORT JS --><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><!-- IMPORT JS --><script>// 基于touch事件模型模拟出“点击”的效果const box = document.querySelector(".box");box.ontouchstart = function (ev) {/*手指按下的时候:记录手指起始的坐标位置ev:TouchEventtouches/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组件库一般都是这样的!
        • 理论上,官方告诉我们图片的处理方案是这样的:
          • 准备三张图 logo.png logo@2x.png logo@3x.png
          • 我们需要根据当前设备的DPR,来决定使用那张图。
        • 只不过前端这样处理太麻烦了,需要写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>
      

参考


http://www.ppmy.cn/news/493941.html

相关文章

Android DiskLruCache完全解析,硬盘缓存的最佳方案

概述 LruCache只是管理了内存中图片的存储与释放&#xff0c;如果图片从内存中被移除的话&#xff0c;那么又需要从网络上重新加载一次图片&#xff0c;这显然非常耗时。对此&#xff0c;Google又提供了一套硬盘缓存的解决方案&#xff1a;DiskLruCache(非Google官方编写&…

求助 !cru改分辨率锁帧60hz

天选二笔记本&#xff0c;玩CSGO没有1280*960分辨率&#xff0c;显卡不支持独显直连&#xff0c;于是用CRU改了分辨率&#xff0c;现在屏幕一卡一卡的不流畅&#xff0c;刷新率从240hz锁的只有64hz&#xff0c;amd显卡驱动也打不开了&#xff0c;我把CRU卸载了也没用&#xff0…

Python opencv videocapture 网络推流/本地视频播放 获取最新帧 获取最后帧 获取实时帧

Python opencv videocapture 获取最新帧 获取最后帧 获取实时帧 获取最新图片 关键代码 allcount cap.get(cv2.CAP_PROP_FRAME_COUNT) cap.set(cv2.CAP_PROP_POS_FRAMES,allcount)完整代码 # -*- coding: utf-8 -*- import cv2 import time# 可以是网络推流地址 也可以是本…

webrtc中音频帧时间戳的打印

采集时封装格式AudioFrame:见Channel::ProcessAndEncodeAudioOnTaskQueue() audio_input->timestamp_ _timeStamp; //_timeStamp初始值为 0 _timeStamp static_cast<uint32_t>(audio_input->samples_per_channel_); audio_input->timestamp_的值为采样个数…

记录HBuilderX将uniapp项目运行到华为手机

解压并运行刚从官网下载的HBuilder X&#xff0c;新建一个项目 一、电脑下载【华为手机助手】并安装 下载地址&#xff1a; https://consumer.huawei.com/cn/support/hisuite/ 二、华为手机设置 1、手机准备&#xff1a;华为&#xff08;没有插入手机卡&#xff09;&#x…

NodeJS File Upload⑩

文章目录 ✨文章有误请指正&#xff0c;如果觉得对你有用&#xff0c;请点三连一波&#xff0c;蟹蟹支持&#x1f618;前言文件上传 后端接口 Form表单上传 Axios前后端分离上传 实现效果演示 记录 读取图片文件总结 ✨文章有误请指正&#xff0c;如果觉得对你有用&a…

苹果保修期_苹果手机怎么查看保修期 查询有效保修状态日期方法

苹果手机怎么查看保修期 查询有效保修状态日期方法 当我们在购买新手机的时候都是有一定的手机保修时间的&#xff0c;在一定的时间范围内手机出现问题都可以进行售后保修&#xff0c;并且不同品牌的手机保修期限会有所不同&#xff0c;查看保修日期的方法也不同。那么很多用户…

苹果保修期查询_保修期还有6个月的IPhone X 换个“新”主板变“过保”了 维修点这样回应...

原创文章 未经允许禁止任何形式转载&#xff0c;侵权必究 河南商报记者 韩忠林 文/图 新买的IPhone X&#xff0c;保修期还有半年&#xff0c;因为意外摔坏&#xff0c;郑州市民郭先生在一家带有“苹果维修服务中心”字样的店铺换了“新”主板后&#xff0c;代表着手机身份的IM…