移动端网页特效
一、触屏事件
1.1概述
移动端的兼容性极佳,无需考虑js的兼容问题,而移动端的独特事件---touch事件(也称为触摸事件),Android和js都有。
touch对象代表一个触摸点,可为手指/触控笔。该事件可响应用户手指对屏幕(或触控板)操作。
- 常见触屏事件:
1.2touchstart事件
手指触碰到DOM元素时触发
<div></div> <script> div.addEventListener('touchstart',function(){ //执行语句; }) </script>
1.3touchmove事件
手指按住DOM元素移动时触发
<div></div> <script> var div = document.querySelector('div'); div.addEventListener('touchmove',function(){ //执行事件 }) </script>
1.4touchend事件
手指摸完离开DOM元素时触发
<div></div> <script> var div = document.querySelector('div'); div.addEventListener('touchend',function(){ //执行事件 }) </script>
1.5触摸事件对象 TouchEvent
TouchEvent是用来描述手指在触摸平面的状态变化的事件。用于描述一个/多个触点
【同鼠标事件对象mouseEvent】
-
如:
触点移动、触点增加和减少等
touchstart、touchmove、touchend都各自有事件对象
- 常见的对象列表:
1.5.1e.touches
获取正在触摸的所有手指点的数量
- 列表形式,可通过length获得列表长度=几个手指
1.5.2e.targetTouches
获取正在触摸当前DOM元素上的手指列表
- 如果侦听的是一个DOM元素,而非document,那么touches和targetTouches获取的是一样的。
要获取第几个手指的相关信息,如:手指坐标,状态等
- 可利用e.targetTouches[下标]得到
1.5.3e.changeTouches
获取手指状态改变的列表
- 从无到有、从有到无
- 手指离开时,仍可获得changeTouches列表
1.6移动端拖动元素
要实现拖动元素,将拖动时手指的x,y坐标赋给盒子即可
①touchstart、touchmove、touchend可实现拖动元素
②但拖动元素需要获取手指的坐标,利用targetTouches[下标]里面的pageX和pageY
③原理:计算手指移动距离,再把它赋给盒子实现拖动效果
- 原来盒子的坐标位置+手指移动的距离=最终距离
- 手指移动的距离:手指滑动中的位置-手指刚开始触摸的位置
- 盒子坐标距离 element.offset
代码思路
(1)定义全局变量
- 手指初始位置:startX、startY
- 盒子初始位置:x、y
(2)触摸元素touchstart: 获取手指初始坐标,同时获得盒子移动前位置
- 手指初始坐标:
- startX=e.targetTouches[0].pageX
- startY=e.targetTouches[0].pageY
- 盒子移动前坐标:
- x = this.offsetLeft
- y = this.offsetTop
- this表示绑定的事件对象,即touchstart事件对象--div
(3)移x动手指 touchmove:计算手指移动距离,并移动盒子
- 手指移动距离:当前手指坐标-手指初始坐标
- moveX = e.targetTouches[0].offsetLeft - startX;
- moveY = e.targetTouches[0].offsetTop - startY;
- 移动盒子:手指移动距离+盒子初始坐标+'px'
- this.style.offsetLeft = x + moveX + 'px';
- this.style.offsetTop = y + moveY + 'px';
❗:手指移动也会触发滚动屏幕,所以要阻止默认的屏幕滚动 e.preventDefault();
❗:移动的盒子必须设置绝对定位,否则无法移动
html+css代码
<style> div{ position: absolute; left: 0; background-color: aqua; width: 200px; height: 200px; } </style> <body> <div></div>
js代码
<script> //(1)获取盒子元素 var div = document.querySelector('div'); //(2)盒子运动前位置 var x = 0; var y = 0; //(3)手指的初始位置 var startX = 0; var startY = 0; //(4)在手指第一次点击时,获得①手指的初始位置+②盒子移动前的位置 div.addEventListener('touchstart',function(e){ startX = e.targetTouches[0].pageX; startY = e.targetTouches[0].pageY; x = this.offsetLeft; y = this.offsetTop; console.log(x); console.log(y); }); //(5)手指移动时,获取①手指移动的位置:当前手指位置-初始手指位置 //②盒子移动位置:手指移动位置+盒子初始位置,赋给盒子 div.addEventListener('touchmove',function(e){ //计算手指移动距离:目前手指位置-手指初始位置 var moveX = e.targetTouches[0].pageX - startX; var moveY = e.targetTouches[0].pageY - startY; //移动盒子:盒子初始位置+手指移动位置 this.style.left = x + moveX + 'px'; this.style.top = y + moveY + 'px'; console.log(this.style.left); console.log(this.style.top); e.preventDefault();//放置手指滑动的屏幕滚动行为 }); </script>
二、移动端常见特效
2.1classList属性
classList属性是HTML5新增的属性,用于返回元素的所有类名列表【ie10以上版本支持】
- 还可用于添加、移除和切换CSS类
(1)添加类
- 直接写类名,即可
element.classList.add(‘类名’)
(2)删除类
element.classList.remove('类名')
(3)切换类
- 有该类,就加上
- 没有该类,就去除
element.classList.toggle('类名')
(4)好处
相比于之前的className,它不会覆盖原先的class,而是在后面追加。
2.2轮播图
1️⃣都可以自动播放图片
2️⃣手指可以拖动播放轮播图
静态页面:
轮播图最前方,加上3
轮播图最后方,加上1
-
ul轮播区域,li放img ,同时设置浮动;
-
ul宽度设置为500%放五张照片
-
li宽度设置为20%,使其放入u
-
要让用户看到1,而非加的3,修改margin-left为-100%
js思路:
1️⃣自动播放效果
①利用定时器,使轮播图自动播放
-
定义变量,每次++,移动距离=变量*图片宽度
-
transform移动 element.style.transform = 'translateX ( 移动的像素 px)'
②因为使用到过渡效果,所以利用transitionend事件,检测过渡事件是否完成,完成后再去判断,使图片跳转回第一张。
-
利用index变量,侦听transitionend事件
-
【正着走】if index>=3 令 index = 0 跳到第一张图
-
去除过渡 ul.style.transition = 'none'
-
translateX = -index * w
-
移动 ul.style.transform = 'translateX('+translateX+'px)'
-
-
【倒着走】if index <0 令 index=2跳到最后一张图
- 去除过渡ul.style.transition = 'none'快速到最后一张
- translateX = -index *w
- 移动ul.style.transform = 'translateX('+translateX+'px)'
2️⃣下方小圆点随图片切换
主要利用classList属性
①把ol中li带有current类名全选出来,去除类名
- element.classList.remove('current')
②再让当前索引号的li加上current类
- element.classList.add('current')
3️⃣手指拖动轮播图
本质就是ul跟着手指动
①touchstart触摸手指,获取手指初始坐标
- 停止定时器,轮播图停止自动播放
②touchmove移动手指
- 计算手指移动距离:当前坐标-初始坐标
- 移动盒子:盒子原先位置+手指移动距离+'px'
- 清除过渡效果
- transform移动
③touchend松开手指
-
根据移动距离决定,向左回弹,还是向右回弹
-
移动距离大于某像素,就播放上一张、下一张滑动
- 注意取绝对值 Math.abs,因为可能左滑/右滑
- 移动距离为正:表示右滑--》播放上一张
- 移动距离为负:表示左滑--》播放下一张
-
移动距离小于某像素,回弹至原来位置
-
-
手指离开再重新开启定时器,让轮播图自动播放
- 先清除,保证只有一个定时器
- 再开启,复制第一次开启的代码即可
4️⃣优化
①鼠标点击不拖动,不进行判断滚动上一张/下一张
- 定义全局变量flag,初值为flase,touchmove鼠标移动中变为true
②手指移动轮播图,阻止屏幕滚动行为
- touchmove事件中,添加e.preventDefault()
完整代码
(1)html部分
<!-- 焦点图模块 --> <div class="focus"> <ul> <!-- 将图片3复制一份到图片1的前面 --> <!-- 为了使得手指移动图片1的时候,前面不会有空白 --> <li><img src="upload/focus3.jpg" alt=""></li> <li><img src="upload/focus1.jpg" alt=""></li> <li><img src="upload/focus2.jpg" alt=""></li> <li><img src="upload/focus3.jpg" alt=""></li> <!-- 复制图片1到图片3的最后 --> <li><img src="upload/focus1.jpg" alt=""></li> </ul> <ol> <li class="current"></li> <li></li> <li></li> </ol> </div>
(2)css部分
/* focus */ .focus { position: relative; padding-top: 44px; overflow: hidden; } .focus img { width: 100%; } .focus ul { width: 500%; margin-left: -100%; } .focus ul li { float: left; width: 20%; } .focus ol { position: absolute; bottom: -9px; right: 5px; } .focus ol li { display: inline-block; width: 5px; height: 5px; background-color: #fff; list-style: none; border-radius: 2px; /* 给ol里的li也就是小圆点加transition过渡,让小圆点的变化更自然 */ transition: all .3s; } .focus ol li.current { width: 15px; }
(3)js部分
window.addEventListener('load', function () {//等整个页面加载完毕,再运用js // 1.获取元素 var focus = document.querySelector('.focus'); var ul = focus.children[0]; var ol = focus.children[1]; // 移动的每张图片的宽度,就是focus宽度 // 获得focus的宽度 var w = focus.offsetWidth; // 2.利用定时器自动轮播图片 // 声明一个变量index来控制ul每次移动 var index = 0; var timer = setInterval(function () { index++; var translatex = -index * w;//因为是往左走,所以是负值 ul.style.transition = 'all .3s';//添加过渡,让图片慢点自动滚动 ul.style.transform = 'translateX(' + translatex + 'px)';//每隔2S,往左滚动一张图片 }, 2000); // 等着过渡完成之后,再去判断 监听过渡完成的事件 transitionend ul.addEventListener('transitionend', function () { // 无缝滚动 // 第一个focus1的index是0,最后一个focus1的index是3 // 当index变为3或更大的时候,跳转回index为0 if (index >= 3) { index = 0; // 去掉过渡,直接跳转 ul.style.transition = 'none'; // 用最新的index*宽度,继续滚动图片 var translatex = -index * w; ul.style.transform = 'translateX(' + translatex + 'px)'; } else if (index < 0) { // 当index<0的时候,跳转回index为2 index = 2; // 去掉过渡,直接跳转 ul.style.transition = 'none'; // 用最新的index*宽度,继续滚动图片 var translatex = -index * w; ul.style.transform = 'translateX(' + translatex + 'px)'; } // 3.小圆点跟随变化效果 // 移除(classList.remove)ol中li中有current类名的li ol.querySelector('li.current').classList.remove('current'); // 给当前index的li添加(classList.add)类名current ol.children[index].classList.add('current'); }); // 4.手指滑动轮播图 // 本质上是让ul跟随手指移动 // 触摸元素(touchstart)获得手指初始坐标 // 此处是左右滑动,所以只需要X坐标 var startX = 0; var moveX = 0;//之后会使用到该移动距离,所以要是全局变量 var flag = false;//声明一个全局变量flag ul.addEventListener('touchstart', function (e) { startX = e.targetTouches[0].pageX; // 手指滑动轮播图的时候,要停止轮播图的自动滚动 // 当手指按下时候,就停止图片自动滚动 clearInterval(timer); }); // 手指滑动(touchmove)获得手指移动距离 ul.addEventListener('touchmove', function (e) { // 手指移动距离=手指滑动时的手指X坐标-手指初始X坐标 moveX = e.targetTouches[0].pageX - startX; // 盒子最终移动距离=盒子之前的移动距离+手指移动的距离 var translatex = -index * w + moveX; // 手指移动的时候不需要过渡效果,所以去掉过渡,直接跳转 ul.style.transition = 'none'; ul.style.transform = 'translateX(' + translatex + 'px)'; flag = true;//如果用户手指移动过再去判断,不然不判断 e.preventDefault();//阻止滚动ul的时候,让屏幕滚动的行为 }); // 手指移开(touchend)根据移动距离判断是 回弹 还是 播放上一张/下一张 ul.addEventListener('touchend', function (e) { if (flag) {//如果用户手指移动过再去判断,不然不判断 // (1)如果移动距离大于50px,则播放上一张/下一张 if (Math.abs(moveX) > 50) { // 如果是右滑,则播放下一张,moveX是正值 if (moveX > 0) { index--; } else { // 如果是左滑,则播放上一张,moveX是负值 index++; } // 用最新的index*宽度,继续滚动图片 var translatex = -index * w; // 图片滚动时要有过渡效果 ul.style.transition = 'all .3s'; ul.style.transform = 'translateX(' + translatex + 'px)'; } else { // (2)如果移动距离小于50px,则回弹 // 用最新的index*宽度,继续滚动图片 var translatex = -index * w; // 图片滚动时要有过渡效果 ul.style.transition = 'all .1s'; ul.style.transform = 'translateX(' + translatex + 'px)'; } } // 手指离开的时候就重新开启定时器 clearInterval(timer);//先清除定时器,保证页面中只有一个定时器 //再开启定时器 timer = setInterval(function () { index++; var translatex = -index * w; ul.style.transition = 'all .3s'; ul.style.transform = 'translateX(' + translatex + 'px)'; }, 2000); }); })
2.3返回顶部
滚动到某个地方,显示[返回顶部],否则隐藏
①滚动到某位置,显示[返回顶部]
-
绑定scroll滚动事件
-
滚动某位置:window.pageY = ?,
- ?表示滚动到某盒子处,可用element.offsetTop获取
-
显示:element.style.display = 'block'
②点击[返回顶部],回到页面顶部
- 利用window.scroll(0,0)返回顶部
(1)html代码
<div class="goBack">返回顶部</div>
(2)css代码
body{ height: 3000px; } .goBack{ position:fixed; bottom:50px; right: 20px; width: 38px; height: 38px; background: url(./img/cloud.png) no-repeat; /* 一开始不显示,移动到某位置显示 */ display: none; }
(3)js代码
var goBack = document.querySelector('.goBack'); //(1)滑动到某位置,显示返回顶部 document.addEventListener('scroll',function(){ if(window.pageYOffset >= 100){ goBack.style.display = 'block'; }else{ goBack.style.display = 'none'; } }); //(2)点击返回顶部,跳转页面上方 document.addEventListener('click',function(){ window.scroll(0,0) })
2.4click延时解决方案
移动端中的click事件有300ms的延时,原因是缩放页面,常使用双击复原缩放页面。
- 因而移动端每次就会等待300ms,防止有下一次的点击
若要使得点击后,不进行延迟等待,解决方案如下:
(1)禁用缩放
禁用浏览器默认双击缩放行为并去除300ms的点击延迟
- html头部添加 content="user-scalable=no"
<meta name="viewport" content="user-scalable=no">
(2)封装事件
利用touch事件自己封装这个事件解决300ms延迟
-
原理:
- 当手指触摸屏幕,记录当前触摸时间
- 当手指离开屏幕,用离开时间-触摸时间
- 若<150ms,且未滑动过屏幕,定义为点击
- 若<150ms,但滑动过屏幕,不定义为点击
(3)fastclick插件
若页面需要缩放效果,第一种✖
若有多个元素需解决延迟,第二种✖
fastclick插件是解决 300ms延迟的js文件
①下载js文件
下载地址:https://github.com/ftlabs/fastclick
②将fastclick.js引入要使用的html页面中
官方上复制,太长了在此不赘述
③按照语法规范,添加js代码
if ('addEventListener' in document) { document.addEventListener('DOMContentLoaded', function() { FastClick.attach(document.body); }, false); }
④至此,该页面中所有click延迟问题都被解决了
三、移动常用开发插件
3.1什么是插件?
js插件是js文件,遵循一定规范编写,方便展示和调用。
- 如:轮播图、瀑布流插件
- 特点:解决某问题而存在,功能单一且小
3.2插件的使用
在github仓库:https://github.com中下载时,都有官方使用说明
(1)下载/拷贝插件
(2)按照文档使用说明
- 寻找想要的demo效果
- 引入css,js文件
- 复制html代码结构
(3)按照官方API说明,修改效果
(4)完成自己页面的代码编写 end
3.3Swiper插件
Swiper插件用于轮播图
中文官网地址https://www.swiper.com.cn
(1)官网下载Swiper
打开官网->点击获取Swiper-》选择下载Swiper
点击下载Swiper版本
(2)引入插件相关文件
解压缩后,demo存放所有示例的html文件
编号对应官网的演示编号
选择需要的js效果,打开html文件
- 根据引入的css文件、js文件位置
- 找解压缩后Swiper文件夹中对应的css、js文件
将其引入在自己的页面中,再复制代码结构修改即可。
②按照规定语法使用
按照demo中html的代码中定义的class
修改自己的代码
(3)拓展
①swiper.css和swiper.min.css是一样的,仅min.css文件经过压缩,因而更小。
②引入时,先引入swiper.js再去引入自己的js
③详细使用见官网:
④更改css样式,可以复制该元素类名,在页面重新修改类样式
-
样式后+ ! important 提升优先级
⑤更改js设置,可根据API文档查找属性,进行修改
3.4superslide插件
官网地址:http://www.superslide2.com/
3.5iscroll插件
官网地址:https://github.com/cubiq/iscroll
3.6视频插件
zy.demia.js可用于pc端+移动端的视频显示,相比于pc端< video control>标签,使用该插件可以统一样式,同时无需自己编写诸多代码。
下载地址 : https://github.com/ireaderlab/zyMedia
四、移动端常用开发框架
框架顾名思义是一套架构,基于自身特点向用户提供一套较为完善的解决方案。
- 框架控制权都在其本身,使用者只能按照规范进行开发
前端常用框架Bootstrap?Vue、Angualer、React等。
前端常用移动端插件swiper、superslide、iscroll等。
4.1框架和插件的区别
框架:大而全,一整套解决方案
插件:小而专一,某个功能的解决方案
4.2Bootstrap框架
官网地址: https://www.bootcss.com/
【注意Bootstrap是基于jQuery实现】
(1)下载框架包
- 包含css和js文件
(2)引入css和js文件
-
在自己的html页面中引入bootstrap的js和css
-
同时注意先引入jquery,再引入boostrap的js
(3)复制代码结构
到Bootsrap官网上复制代码结构
(4)自行修改样式