技术好文共享:移动端事件(二)——移动端滑屏切换的幻灯片

简介: 技术好文共享:移动端事件(二)——移动端滑屏切换的幻灯片

经过昨天对移动端基础的了解,今天就来用原生JS实现一下我们的幻灯片。


因为是用原生实现,所以本文篇幅较长,各位看官只需理解思路即可,代码部分可以粗略看看。


毕竟我们有better-scroll这样封装好的框架能更快速实现效果。b( ̄▽ ̄)d 


首先根据我们昨天的滑屏操作,先将幻灯片的滑屏效果做出来。这里大家将照片地址更换成自己的就能得到效果。


案例要在客户端才有效果哦,如果在PC端,网页中右键点审查,控制器旁边有个手机图标,点击下图这个也能有效果。


Document


html {


font-size: 10vw;


}


body {


margin: 0;


}


ul {


margin: 0;


padding: 0;


list-style: none;


}


#wrap {


position: relative;


width: 100vw;


overflow: hidden;


}


#list {


float: left;


display: flex;


display: -webkit-box;


}


#list li {


flex: none;


width: 100vw;


}


#list img {


width: 100%;


display: block;


}


.nav {


position: absolute;


left: 0;


bottom: .2rem;


width: 100%//代码效果参考:http://hnjlyzjd.com/hw/wz_25260.html

;

text-align: center;


vertical-align: top;


}


.nav a {


display: inline-block;


width: .3rem;


height: .3rem;


background: #fff;


margin: 0 .1rem;


border-radius: .15rem;


transition: .3s;


}


.nav .active {


width: .6rem;


color: #fff; //代码效果参考:http://hnjlyzjd.com/hw/wz_25258.html


}


// 幻灯片效果


{


let wrap = document.querySelector("#wrap");


let list = document.querySelector("#list");


let navs = document.querySelectorAll(".nav a");


let translateX = 0; //元素的移动位置


let startPoint = {}; //摁下时手指坐标


let disPoint = {};//手指移动距离


let startX = 0;//摁下时元素坐标


wrap.addEventListener("touchstart",({changedTouches})=>{


startPoint = {


x: changedTouches【0】.pageX,


y: changedTouches【0】.pageY


};


startX = translateX;


});


wrap.addEventListener("touchmove",(e)=>{


let touch = e.changedTouches【0】;


let nowPoint = {


x: touch.pageX,


y: touch.pageY


};


disPoint = {


x: nowPoint.x - startPoint.x,


y: nowPoint.y - startPoint.y


};


translateX = disPoint.x + startX;


list.style.transform = translateX(${translateX}px);


});


}


滑屏效果做出来以后,我们给它添加动画,接下来为了大家方便看,就只写JavaScript的代码。红色的为添加的新代码。


// 幻灯片效果


{


let wrap = document.querySelector("#wrap");


let list = document.querySelector("#list");


let navs = document.querySelectorAll(".nav a");


let translateX = 0; //元素的移动位置


let startPoint = {}; //摁下时手指坐标


let startX = 0;//摁下时元素坐标


let disPoint = {};//手指移动距离


let now = 0; // 记录当前在第几张


const Range = .3 wrap.clientWidth; // 移动超过屏幕 30% 时,抬起切换到下一张


wrap.addEventListener("touchstart",({changedTouches})=>{


list.style.transition = "none";


startPoint = {


x: changedTouches【0】.pageX,


y: changedTouches【0】.pageY


};


startX = translateX;


});


wrap.addEventListener("touchmove",(e)=>{


let touch = e.changedTouches【0】;


let nowPoint = {


x: touch.pageX,


y: touch.pageY


};


disPoint = {


x: nowPoint.x - startPoint.x,


y: nowPoint.y - startPoint.y


};


translateX = disPoint.x + startX;


list.style.transform = translateX(${translateX}px);


});


wrap.addEventListener("touchend",()=>{


if(Math.abs(disPoint.x)>Range){ //切换到下一张


//console.log(disPoint.x/Math.abs(disPoint.x));


now -= disPoint.x/Math.abs(disPoint.x);


// 求当前要看第几张


}


translateX = -nowwrap.clientWidth;


list.style.transition = ".3s";


list.style.transform = translateX(${translateX}px);


//console.log(now);


});


}


这一步我们将每次手指离开屏幕后进行判断,判断手指移动的距离是否超过30%,抬起则切换到下一张。我们在每次切换时添加了0.3s的延迟动画。因为这延迟动画在手指触屏时就会生效,所以我们在touchstart的时候将它清除。


我们实现上面效果后,可以发现会有划出去的风险,接下来我们要实现无缝滚动


在此之前,我们要了解实现无缝滚动的原理,下面我做了个图,一目了然,如果有不明白可以评论联系我。


原理就是:当用户往第一组的第一张滑动时,我们将他移动到第二组的第一张。


      当用户网第二组最后一张滑动时,我们将他移动到第一组的最后一张。


// 幻灯片效果


{


let wrap = document.querySelector("#wrap");


let list = document.querySelector("#list");


let navs = document.querySelectorAll(".nav a");


let translateX = 0; //元素的移动位置


let startPoint = {}; //摁下时手指坐标


let startX = 0;//摁下时元素坐标


let disPoint = {};//手指移动距离


let now = 0; // 记录当前在第几张


const Range = .3 wrap.clientWidth; // 移动超过屏幕 30% 时,抬起切换到下一张


list.innerHTML += list.innerHTML; // 把 list 图片复制一份


wrap.addEventListener("touchstart",({changedTouches})=>{


list.style.transition = "none";


startPoint = {


x: changedTouches【0】.pageX,


y: changedTouches【0】.pageY


};


if(now === 0){


now = navs.length;


} else if(now === navs.length2-1){


now = navs.length - 1;


}


translateX = -nowwrap.clientWidth;


list.style.transform = translateX(${translateX}px);


startX = translateX;


});


wrap.addEventListener("touchmove",(e)=>{


let touch = e.changedTouches【0】;


let nowPoint = {


x: touch.pageX,


y: touch.pageY


};


disPoint = {


x: nowPoint.x - startPoint.x,


y: nowPoint.y - startPoint.y


};


translateX = disPoint.x + startX;


list.style.transform = translateX(${translateX}px);


});


wrap.addEventListener("touchend",()=>{


if(Math.abs(disPoint.x)>Range){ //切换到下一张


//console.log(disPoint.x/Math.abs(disPoint.x));


now -= disPoint.x/Math.abs(disPoint.x);


// 求当前要看第几张


}


translateX = -nowwrap.clientWidth;


list.style.transition = ".3s";


list.style.transform = translateX(${translateX}px);


});


}


实现这一效果,首先我们将图片复制多一份,然后在手指点击屏幕时,


  判断现在是否是第一组的第一张,是则跳转到第第二组的第一张


  或者是否为第二组的最后一张,是则跳转到第一组的最后一张。


    对其style里的translateX进行进行更改就能实现无缝滚动。


接着我们对下面的白点进行同步,只用在touchend下添加以下代码即可


// 同步 nav


navs.forEach(item=>{


item.classList.remove("active");


});


navs【now%navs.length】.classList.add("active");


至此我们已经完成一个比较简单的移动端轮播。


但是


我们还有bug,就是当用户斜向上滑动时,轮播与下面内容皆会滑动。


因此我们需要做:


1. 判断用户想要滑动的是幻灯片,还是想要滚动滚动条


2. 如果想要滑动幻灯片,就阻止滚动条


3. 如果想要滚动滚动条,就阻止幻灯片


4. 注意 一旦在滑动的过程中判断到用户的滑动方向之后,就不在做方向修改


以下便是所有效果


Document


html {


font-size: 10vw;


}


body {


margin: 0;


}


ul {


margin: 0;


padding: 0;


list-style: none;


}


#wrap {


position: relative;


width: 100vw;


overflow: hidden;


}


#list {


float: left;


display: flex;


display: -webkit-box;


}


#list li {


flex: none;


width: 100vw;


}


#list img {


width: 100%;


display: block;


}


.nav {


position: absolute;


left: 0;


bottom: .2rem;


width: 100%;


text-align: center;


vertical-align: top;


}


.nav a {


display: inline-block;


width: .3rem;


height: .3rem;


background: #fff;


margin: 0 .1rem;


border-radius: .15rem;


transition: .3s;


}


.nav .active {


width: .6rem;


color: #fff;


}


.textList {


margin: 0;


padding: 0;


list-style: none;


}


.textList li {


font: 14px/40px "宋体";


padding-left: 20px;


border-bottom: 1px solid #000;


}


"use strict";


// 补充列表内容


{


var txtList = document.querySelector(".textList");


txtList.innerHTML = 【...(".".repeat(100))】.map(function (item, index) {


return "\u8FD9\u662F\u7B2C" + index + "\u4E2Ali";


}).join("");


} // 幻灯片


/


判断用户滑动方向时:


一旦判断到用户的滑动方向,就认定该次操作用户想要进行上下或左右滑动,中间不再修改,一直到用户下一次再执行 start


/


{


var wrap = document.querySelector("#wrap");


var list = document.querySelector("#list");


list.innerHTML += list.innerHTML; // 把图片复制一份用来处理无缝


var startPoint = {}; // 摁下时手指位置


var startX = 0; // 摁下时元素的位置


var translateX = 0; // 元素的 tranlateX 值


var now = 0; //记录当前在第几张


var navs = document.querySelectorAll(".nav a");


var RANGE = wrap.clientWidth .3; //超过该幅度切换上一张下一张


var isMove = false; // 是否需要滑动幻灯片


var isDir = true; // 记录是否已经判断到了方向 true 还没有判断到方向,false已经判断到了方向


wrap.addEventListener("touchstart", function (_ref) {


var changedTouches = _ref.changedTouches;


list.style.transition = "none";


var touch = changedTouches【0】;


startPoint = {


x: touch.pageX,


y: touch.pageY


};


if (now == 0) {


//第1组第0张会有划出去的风险


now = navs.length;


} else if (now == navs.length 2 - 1) {


// 第2组最后一张,有划出去的风险


now = navs.length - 1;


}


translateX = -now wrap.clientWidth;


list.style.WebkitTransform = list.style.transform = "translateX(" + translateX + "px)";


startX = translateX;


isMove = false;


isDir = true;


});


wrap.addEventListener("touchmove", function (e) {


var touch = e.changedTouches【0】;


var nowPoint = {


x: touch.pageX,


y: touch.pageY


};


var dis = {


x: nowPoint.x - startPoint.x,


y: nowPoint.y - startPoint.y


}; // 判断方向根据需求来阻止默认事件


if (isDir) {


if (Math.abs(dis.x) - Math.abs(dis.y) > 5) {


// 左右滑动


isMove = true;


isDir = false;


} else if (Math.abs(dis.y) - Math.abs(dis.x) > 5) {


// 上下滑动


isMove = false;


isDir = false;


}


e.preventDefault();


}


console.log(isMove, isDir);


if (isMove) {


translateX = startX + dis.x;


list.style.WebkitTransform = list.style.transform = "translateX(" + translateX + "px)";


e.preventDefault();


}


});


wrap.addEventListener("touchend", function (_ref2) {


var changedTouches = _ref2.changedTouches;


var touch = changedTouches【0】;


var nowPoint = {


x: touch.pageX,


y: touch.pageY


};


var dis = {


x: nowPoint.x - startPoint.x,


y: nowPoint.y - startPoint.y


}; // 当移动的距离超过图片宽度的 30% 时 切换至下一张或上一张,否则回到当前张


if (Math.abs(dis.x) >= RANGE && isMove) {


// 切换上一张下一张


//console.log(dis.x,dis.x/Math.abs(dis.x));


now -= dis.x / Math.abs(dis.x);


} //console.log(-nowwrap.clientWidth);


translateX = -now * wrap.clientWidth;


list.style.transition = ".3s";


list.style.WebkitTransform = list.style.transform = "translateX(" + translateX + "px)";


navs.forEach(function (nav) {


nav.classList.remove("active");


});


navs【now % navs.length】.classList.add("active");


});


}

相关文章
|
3月前
|
前端开发 图形学 开发者
【独家揭秘】那些让你的游戏瞬间鲜活起来的Unity UI动画技巧:从零开始打造动态按钮,提升玩家交互体验的绝招大公开!
【9月更文挑战第1天】在游戏开发领域,Unity 是最受欢迎的游戏引擎之一,其强大的跨平台发布能力和丰富的功能集让开发者能够迅速打造出高质量的游戏。优秀的 UI 设计对于游戏至关重要,尤其是在手游市场,出色的 UI 能给玩家留下深刻的第一印象。Unity 的 UGUI 系统提供了一整套解决方案,包括 Canvas、Image 和 Button 等组件,支持添加各种动画效果。
167 3
|
7月前
|
缓存 UED 开发者
【专栏:交互与用户体验篇】网页加载动画与用户等待体验
【4月更文挑战第30天】网页加载动画在现代设计中扮演重要角色,通过提供视觉反馈和分散注意力,改善用户体验。本文讨论了设计加载动画的原因和类型,如进度指示器、旋转指针、动态图标、模糊效果和文本提示,并提出了设计最佳实践:简洁相关、快速明确、考虑不同设备和避免误导。优化加载策略,如首屏内容优先加载和懒加载,也是提升用户体验的关键。设计时需注重实用性、品牌一致性和跨平台兼容性,确保在加载延迟时仍能给用户留下良好印象。
105 5
|
7月前
【实用】一个移动端简单的UI弹窗组件,虽算不上高大上,但至少耐看
【实用】一个移动端简单的UI弹窗组件,虽算不上高大上,但至少耐看
|
7月前
|
缓存 小程序 数据可视化
【社区每周】小程序授权弹层和菜单支持长辈版、无障碍版;AMPE情景智能新增widget卡片能力(2022年6月第一期)
【社区每周】小程序授权弹层和菜单支持长辈版、无障碍版;AMPE情景智能新增widget卡片能力(2022年6月第一期)
38 0
|
Web App开发 编解码 移动开发
探秘移动端网页调用摄像头的两种方式
PC 端网页调用摄像头的场景想必大家并不陌生,打开一个网址,开启摄像头开始笔试/视频聊天/直播等。 而在移动端网页调用摄像头的场景你见得多吗?我想答案应该是不多吧(在下见识浅薄)。
|
搜索推荐 UED
使用 fluro 的转场动画提高页面切换体验
fluro 提供了滑入、渐现、全屏对话框、原生等多种转场动画形式,同时还支持自定义转场动画。借助转场动画可以提高用户体验。
278 0
使用 fluro 的转场动画提高页面切换体验
|
API Android开发
全屏、沉浸式、fitSystemWindow使用及原理分析:全方位控制“沉浸式”的实现
全屏、沉浸式、fitSystemWindow使用及原理分析:全方位控制“沉浸式”的实现
983 0
全屏、沉浸式、fitSystemWindow使用及原理分析:全方位控制“沉浸式”的实现
Dsicuz移动端二开之关注和粉丝页面以及关注状态处理(2)
Dsicuz移动端二开之关注和粉丝页面以及关注状态处理
184 0
Dsicuz移动端二开之关注和粉丝页面以及关注状态处理(2)
|
PHP 数据库
Dsicuz移动端二开之关注和粉丝页面以及关注状态处理(1)
Dsicuz移动端二开之关注和粉丝页面以及关注状态处理
199 0
Dsicuz移动端二开之关注和粉丝页面以及关注状态处理(1)
|
缓存 运维 前端开发
从零开始实现放置游戏(十四)——实现战斗挂机(5)地图移动和聊天
上一节添加了websocket组件,实现了前后端通信。后面我们只需要根据游戏的业务逻辑,逐步实现各种功能即可。   另外,在实现具体业务逻辑时,发现上一章设计的消息对象有些不合理,由于粒度过粗,导致可以复用的部分很少,且这里的通信模型并不是一个请求对应一个响应的模式。比如:玩家a从地图A移动到地图B。此时,a发送移动请求。服务器返回B地图的信息和在线列表给A。同时还要发送最新的在线列表给地图B的其他玩家b,c,d....这里其他玩家并没有发送请求,但收到了响应消息。因此,将消息类型重构成由客户端发出的消息和由服务端发出的消息两类,分别以"3000"和"6000"开头。
从零开始实现放置游戏(十四)——实现战斗挂机(5)地图移动和聊天