原生JS实现移动端web轮播图详解(结合Tween算法造轮子)

前言

相信大家应该都知道,移动端的轮播图是我们比较常见的需求, 我们最快的实现方式往往是 使用第三方的代码, 例如 swiper , 但当遇到一些比较复杂的轮播图需求时, 往往是束手无策,不知道怎么改.

所以我们要尝试去自己造一些轮子, 以适应各种复杂多变的需求;  另外一点, 自己写的代码如果有bug是很容易修复的, 对自身的提高也很大.

在没有阅读swiper源码的过程下,我尝试自己实现一个简易而不失实用的移动端轮播图, 经过几个小时的思考和实践终于还是实现了(如图):

实现移动端的轮播图要比pc复杂一些,主要表现在以下几个方面:

1.轮播图要适应不同宽度/dpr的屏幕

2.需要使用 touch相关的事件

3.不同机型对 touch事件支持的不太一样,可能会有一些兼容性问题

4.手指移动图片一部分距离,剩下的距离需要自动完成

5.自动完成距离需要有 ease 时间曲线

但编程解决问题的思路都是差不多的,

我们在使用轮播图的时候可以仔细观察,通过现象看到本质:

  • 我们在使用轮播图的时候可以仔细观察,通过现象看到本质:
  • 手指放在图片上, 手指向左或者向右移动, 图片也随之移动;
  • 手指移动的距离少时,图片自动复原位置;手指移动的距离多时,自动切换到下一张;
  • 手指向左或者向右移动的快时,会切换到下一张;
  • 图片轮播是无限循环的, 我们需要采用  3 1 2 3 1的方式来实现, 即 N+2张图来实现N张图的无限循环轮播

我们通过分析现象,可以提出一个基本实现方案:

1. 手指触摸事件可以通过 touchstart touchmove touchend 3个事件来实现

2.在手指 touchstart的时候我们需要记录 手指的x坐标,  可以使用 touch的pageX属性; 还有 这个时间点,

3.手指touchmove的时候我们也需要记录pageX,并且记录累计移动的距离 moveX

4.手指离开的时候,记录时间点, 根据前两步计算的 x方向移动的距离,时间点之差

5.通过比较x方向移动距离来判断移动方向, 以及是否应该切换到下一张图; 根据时间判断用户是否进行了左右扫动的操作

6.移动图片可以使用 translate3d来实现,开启硬件加速

7.移动一段距离需要 easeOut效果,我们可以使用 Tween算法中的easeOut来实现我们每次移动的距离; 当然也可以使用 js设置 transition动画

实现源码(仅供参考):

head头部样式

<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width,initial-scale=.5,maximum-scale=.5">
 <title>移动端轮播图</title>
 <style>
 * {
 box-sizing: border-box;
 margin: 0;
 padding: 0
 }
 .banner {
 overflow: hidden;
 width: 100%;
 height: 300px
 }
 .banner .img-wrap {
 position: relative;
 height: 100%
 }
 .banner img {
 display: block;
 position: absolute;
 top: 0;
 width: 100%;
 height: 100%
 }
 </style>
</head> 

HTML结构

<div class="banner">
 <div class="img-wrap" id="imgWrap">
 <img src="images/banner_3.jpg" data-index="-1">
 <img src="images/banner_1.jpg" data-index="0">
 <img src="images/banner_2.jpg" data-index="1">
 <img src="images/banner_3.jpg" data-index="2">
 <img src="images/banner_1.jpg" data-index="3">
 </div>
</div> 

JS代码1, easeOut动画式移动,

这里的   HTMLElement.prototype.tweenTranslateXAnimate ,是给所有的HTML元素类扩展的tweenTranslateXAnimate方法

移动一段距离我们需要使用定时器来帮助我们完成,这个重复的操作

<script>
 HTMLElement.prototype.tweenTranslateXAnimate = function (start, end, callback) {
 var duration = 50;
 var t = 0;
 var vv = end - start;
 var Tween = {
 Quad: {
 easeOut: function (t, b, c, d) {
  return -c * (t /= d) * (t - 2) + b;
 }
 }
 }; 

 this.timer = setInterval(function () {
 var dis = start + Tween.Quad.easeOut(++t, 0, vv, duration);
 this.style.transform = 'translate3d(' + dis + 'px, 0, 0)';
 if (vv > 0 && parseInt(this.style.transform.slice(12)) >= end) {
 this.style.transform = 'translate3d(' + parseInt(dis) + 'px, 0, 0)';
 clearInterval(this.timer);
 callback && callback();
 }
 if (vv < 0 && parseInt(this.style.transform.slice(12)) <= end) {
 this.style.transform = 'translate3d(' + parseInt(dis) + 'px, 0, 0)';
 clearInterval(this.timer);
 callback && callback();
 }
 }.bind(this), 4);
 }
</script> 

touch事件部分

<script>
 ~function () {
 var lastPX = 0; // 上一次触摸的位置x坐标, 需要计算出手指每次移动的一点点距离
 var movex = 0; // 记录手指move的x方向值
 var imgWrap = document.getElementById('imgWrap');
 var startX = 0; // 开始触摸时手指所在x坐标
 var endX = 0; // 触摸结束时手指所在的x坐标位置
 var imgSize = imgWrap.children.length - 2; // 图片个数
 var t1 = 0; // 记录开始触摸的时刻
 var t2 = 0; // 记录结束触摸的时刻
 var width = window.innerWidth; // 当前窗口宽度
 var nodeList = document.querySelectorAll('#imgWrap img'); // 所有轮播图节点数组 NodeList 

 // 给图片设置合适的left值, 注意 querySelectorAll返回 NodeList, 具有 forEach方法
 nodeList.forEach(function (node, index) {
 node.style.left = (index - 1) * width + 'px';
 }); 

 /**
 * 移动图片到当前的 tIndex索引所在位置
 * @param {number} tIndex 要显示的图片的索引
 * */
 function toIndex(tIndex) {
 var dis = -(tIndex * width);
 var start = parseInt(imgWrap.style.transform.slice(12));
 // 动画移动
 imgWrap.tweenTranslateXAnimate(start, dis, function () {
 setTimeout(function () {
  movex = dis;
  if (tIndex === imgSize) {
  imgWrap.style.transform = 'translate3d(0, 0, 0)';
  movex = 0;
  }
  if (tIndex === -1) {
  imgWrap.style.transform = 'translate3d(' + width * (1 - imgSize) + 'px, 0, 0)';
  movex = -width * (imgSize - 1);
  }
 }, 0);
 });
 } 

 /**
 * 处理各种触摸事件 ,包括 touchstart, touchend, touchmove, touchcancel
 * @param {Event} evt 回调函数中系统传回的 js 事件对象
 * */
 function touch(evt) {
 var touch = evt.targetTouches[0];
 var tar = evt.target;
 var index = parseInt(tar.getAttribute('data-index'));
 if (evt.type === 'touchmove') {
 var di = parseInt(touch.pageX - lastPX);
 endX = touch.pageX;
 movex += di;
 imgWrap.style.webkitTransform = 'translate3d(' + movex + 'px, 0, 0)';
 lastPX = touch.pageX;
 }
 if (evt.type === 'touchend') {
 var minus = endX - startX;
 t2 = new Date().getTime() - t1;
 if (Math.abs(minus) > 0) { // 有拖动操作
  if (Math.abs(minus) < width * 0.4 && t2 > 500) { // 拖动距离不够,返回!
  toIndex(index);
  } else { // 超过一半,看方向
  console.log(minus);
  if (Math.abs(minus) < 20) {
  console.log('距离很短' + minus);
  toIndex(index);
  return;
  }
  if (minus < 0) { // endX < startX,向左滑动,是下一张
  toIndex(index + 1)
  } else { // endX > startX ,向右滑动, 是上一张
  toIndex(index - 1)
  }
  }
 } else { //没有拖动操作 

 }
 }
 if (evt.type === 'touchstart') {
 lastPX = touch.pageX;
 startX = lastPX;
 endX = startX;
 t1 = new Date().getTime();
 }
 return false;
 } 

 imgWrap.addEventListener('touchstart', touch, false);
 imgWrap.addEventListener('touchmove', touch, false);
 imgWrap.addEventListener('touchend', touch, false);
 imgWrap.addEventListener('touchcancel', touch, false); 

 }(); 

</script> 

在触摸事件中最关键的参数是  pageX参数, 记录x的位置.

当然这只是一个demo,还需要进一步的优化和封装, 以便于我们用在真实的项目.

本demo仅仅是提供了一个解决问题的思路, 有了这个思路,相信各种复杂的需求也得以解决...

本文中使用的 tween算法来实现 ease-out效果 ,也可以使用 transtion动画实现, 代码更加简洁,参见轮播图优化篇: http://www.jb51.net/article/123304.htm

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • JavaScript实现移动端轮播效果

    这个轮播代码不是我自己所写,是偶然游览一个简友的主页看到的,今天刚看了事件,决定来逐行分析一下这个代码.首先,移动端与电脑端不同的是移动端只能通过触摸和手势来发生行为,所以我们要用到js中的与触摸操作有关的新事件.其实我们轮播的原理和以前相同,都是通过改变元素的位置来控制图片的出现,但让我们不是很上手的,是那些用于跟踪触摸的属性. 下面,我简单介绍一下与触摸相关的知识 触摸事件 touchstart:当手指触摸屏幕时触发,一只手指放在屏幕上也会触发 touchmove:当手指在屏幕上滑动时连续触

  • 利用纯js + transition动画实现移动端web轮播图详解

    前言 在上一篇文章中,我们使用 tween算法实现了 ease-out移动效果, 其实更简洁的方法是使用 css3的 transition动画,下面话不多说了,来一起看看详细的介绍吧. 核心点: 在 我们通过代码来移动一段距离的时候, 使用 transion动画;在手指移动的时候,不使用transition动画. 使用 transition实现的动画效果的轮播图js代码不足100行 ~function () { var lastPX = 0; // 上一次触摸的位置x坐标, 需要计算出手指每次移

  • js实现移动端轮播图效果

    本文实例为大家分享了移动端轮播图效果展示的具体代码,供大家参考,具体内容如下 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, max

  • 原生js实现移动开发轮播图、相册滑动特效

    使用方法: 分别引用css文件和js文件 如: <link rel="stylesheet" type="text/css" href="css/photoSlider.min.css" /> <script src="js/photoSlider.min.js" type="text/javascript" charset="utf-8"></script

  • 支持移动端原生js轮播图

    直接上代码,自行复制粘贴,本人是新手,欢迎指正. <!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8"> <title>轮播图</title> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-sca

  • JS仿京东移动端手指拨动切换轮播图效果

    如今,移动端web页面在市场上也是占有相当大的比例,而移动端的轮播图效果也是很常见的,今天我就来记录下关于实现一组适用于移动端的可用手指进行拨动切换轮播图的效果. 这个效果的主要技术点依托于触屏设备特有的touch事件:好了,接下来就进入主题吧. 首先是html布局: 1. 这里强调的是记得给html加上viewport这个适口属性. 2. 由于在拨动第一张图片以及最后一张图片的时候需要切换到最后一张以及第一张,要想达到理想效果,需要给第一张图片前面加上最后一张图片,而在最后一张图片后加上第一张

  • flexslider.js实现移动端轮播

    效果如下: 代码如下: <!doctype html> <html> <head> <meta charset="utf-8"> <title>flexslider.js移动端轮播</title> <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" name="

  • Javascript实现视频轮播在pc端与移动端均可

    最近客户要求用Javascript实现视频轮播: 有兴趣的同学可以参开一下 下面写了一个程序实现视频轮播,pc端与移动端均可以实现, 但移动端,存在有一点bug; 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <met

  • 原生JS实现移动端web轮播图详解(结合Tween算法造轮子)

    前言 相信大家应该都知道,移动端的轮播图是我们比较常见的需求, 我们最快的实现方式往往是 使用第三方的代码, 例如 swiper , 但当遇到一些比较复杂的轮播图需求时, 往往是束手无策,不知道怎么改. 所以我们要尝试去自己造一些轮子, 以适应各种复杂多变的需求;  另外一点, 自己写的代码如果有bug是很容易修复的, 对自身的提高也很大. 在没有阅读swiper源码的过程下,我尝试自己实现一个简易而不失实用的移动端轮播图, 经过几个小时的思考和实践终于还是实现了(如图): 实现移动端的轮播图要

  • 原生js实现移动端Touch轮播图的方法步骤

    Touch 轮播图 touch轮播图其实就是通过手指的滑动,来左右切换轮播图,下面我们通过一个案例,来实现下. 1. html 结构 结构上,还是用ul.li来存放轮播图片,ol.li来存放轮播小圆点: 2. 样式初始化 html的一些标签,都会有一些默认样式,比如body标签默认是有一个边距的,为了不影响美观,我们需要清除掉. /* 清除标签默认边距 */ body,ul,li,ol,img { margin: 0; padding: 0; } /* 清除 ul 等标签前面的"小圆点"

  • vue.js项目使用原生js实现移动端的轮播图

    目录 前言 一.了解原生js移动端的事件 二.轮播图实战 第一部分:template模板 第一部分解读: 第二部分:script标签内代码 第二部分解读: 第三部分:css样式部分 三.效果图 结束语 前言 今天我在vue.js项目实战开发过程中遇到了实现轮播图效果的问题,因为不想因为一个轮播图而引用整个jquery,而且我还发现自己根本就不清楚移动端的一些事件,所以我就进行了一些资料查找,并最终解决了这个问题,接下来跟大家分享一下我的解决问题的过程. 一.了解原生js移动端的事件 原生js移动

  • 原生js实现移动端触摸轮播的示例代码

    PC端上实现图片轮播效果很简单,只要通过使用click事件就可以非常简单的实现效果,但是在移动端上,就要通过核心的touch事件来实现. 下面是移动端手指滑动轮播图的完整代码. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, user-scala

  • jquery 实现轮播图详解及实例代码

    轮播图: 接触jquery也有一段时间了,今天刚好利用轮播图来练练手.博文的前面会介绍一个简单用jquery做轮播图的例子,中间会插入一些关于轮播图更多的思考,在后面会用Javascript的方法来写一个轮播图,最后则是关于jquery和Javascript的比较.轮播图的效果可以点击如下链接查看:http://sandbox.runjs.cn/show/t07kscph jquery做轮播图的例子: html部分代码: <!DOCTYPE html> <html> <hea

  • jquery  实现轮播图详解及实例代码

    轮播图: 接触jquery也有一段时间了,今天刚好利用轮播图来练练手.博文的前面会介绍一个简单用jquery做轮播图的例子,中间会插入一些关于轮播图更多的思考,在后面会用Javascript的方法来写一个轮播图,最后则是关于jquery和Javascript的比较.轮播图的效果可以点击如下链接查看:http://sandbox.runjs.cn/show/t07kscph jquery做轮播图的例子: html部分代码: <!DOCTYPE html> <html> <hea

  • 微信小程序 swiper组件轮播图详解及实例

    微信小程序 swiper组件轮播图 照着开发文档尝试,总是能有所收获.之前做Android开发,做个轮播图并不简单,用上viewpage再设置圆点,折腾一通之后还一堆bug.今天尝试微信小程序开发做轮播图,真是感动的泪流满面.废话说完了,上图. 上图就是一个简易的轮播图,是不是很简易.23333 主要是代码也很简单. 1.index.wxml <!--index.wxml--> <swiper class="swiper" indicator-dots="t

  • JS实现点击拉拽轮播图pc端移动端适配

    <div class="content"> <button class="left">left</button> <button class="right">right</button> <div class="index"></div> <div class="lists"> <!--<!–widt

  • JS原生带小白点轮播图实例讲解

    咱们刚刚说了js原生轮播图,现在给他加上可以随着一起走动的小圆点吧! css代码: *{ margin:0px; padding: 0px; } ul{ width: 2500px; height: 300px; position: absolute; } li{ float: left; list-style: none; } img{ width: 500px; height: 300px; } div{ width: 500px; height: 300px; margin: 50px a

随机推荐