视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
具体介绍如何用H5实现触屏版的轮播器
2020-11-27 15:11:37 责编:小OO
文档


本篇文章主要介绍了如何用H5实现一个触屏版的轮播器,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

初入前端,分享一下手机上触屏版轮播器的实现过程,大致功能如下:

1、支持循环滑动

2、宽度可任意设置,不需要与屏幕等宽

3、页面可纵向滚动

4、可设置回调监听元素的切换

5、纯js,不借助任何第三方库

原理

1、假设子元素.item的width为375px,使用绝对定位将所有子元素放在父元素内

2、将父元素.carousel的width设置为375px,与子元素.item宽度相同

3、为父元素.carousel添加触摸事件:touchstart, touchmove, touchend

4、手指按下时,保存初始位置(clientX)

5、手指滑动时,通过滑动距离判断滑动的方向:

①手指向左滑动,则同时移动当前元素和当前元素右边的元素

②手指向右滑动,则同时移动当前元素和当前元素左边的元素

6、手指抬起时,通过滑动距离判断是否切换到下一页

①移动距离未超过子元素宽度的50%,将当前页面回滚到初始位置,不切换当前元素。

②移动距离超过子元素宽度的50%,切换当前元素为下一个元素。

③将当前元素的transform属性设置为translate3d(0px, 0px, 0px),并将z-index属性+1

④将下一个子元素的transform属性设置为translate3d(375px, 0px, 0px),并将z-index属性+1

⑤将上一个子元素的transform属性设置为translate3d(-375px, 0px, 0px),并将z-index属性+1

⑥将其他所有子元素的z-index属性设置为默认值

7、第一个子元素的上一个元素是最后一个元素,最后一个元素的下一个元素是第一个元素,该步骤通过循环链表实现。

移动时设置的是子元素.item的transform属性,而不是父元素.carousel

实现步骤

html&css

//html
<p class="carousel" ontouchstart="" > 
 <p class="item" style="background: #3b76c0" > 
 <h3 >item-1</h3> 
 </p> 
 <p class="item" style="background: #58c03b;"> 
 <h3>item-2</h3> 
 </p> 
 <p class="item" style="background: #c03b25;"> 
 <h3>item-3</h3>
 </p> 
 <p class="item" style="background: #e0a718;"> 
 <h3>item-4</h3> 
 </p> 
 <p class="item" style="background: #c03eac;"> 
 <h3>item-5</h3> 
 </p>
</p>
//css
.carousel{
 height: 50%;
 position: relative;
 overflow: hidden;
}

.item {
 position: absolute;
 left: 0;
 top: 0;
 width: 100%;
 height: 100%;
}

js

设置初始状态

首先实现一个双向链表,用于维护轮播组件中的元素。

function Node(data) {
 this.data = data;
 this.prev = null;
 this.next = null;
 this.index = -1;
}

//双向循环列表
function LinkList() {
 var _nodes = [];
 this.head = null;
 this.last = null;

 if (typeof this.append !== "function") {
 LinkList.prototype.append = function (node) {
 if (this.head == null) {
 this.head = node;
 this.last = this.head;
 }
 else {
 this.head.prev = node;
 this.last.next = node;

 node.prev = this.last;
 node.next = this.head;

 this.last = node;
 }

 node.index = _nodes.length; //务必在push前设置node.index
 _nodes.push(node);
 }
 }
}

有了链表之后,创建一个链表实例,将子元素添加进链表内,并设置一些初始状态

var _container = document.querySelector("." + containerClass);
var _items = document.querySelectorAll("." + itemClass);

var list = loop ? new LinkList() : new SingleList();
for(var i = 0; i < _items.length; i++) {
 list.append(new Node(_items[i]));
}

var _prev = null; //保存之前显示的元素
var _current = list.head; //保存当前显示的元素,默认为第一个元素

var _normalZIndex = _current.data.style.zIndex; //未显示元素的z-index值
var _activeZIndex = _normalZIndex + 1; //当前显示元素的z-index值

var _itemWidth = _current.data.offsetWidth; //子元素宽度

positionItems(); //初始化元素位置
zindexItems(_current, _activeZIndex); //将当前元素及其左右元素的z-index加1

绑定触摸事件

touchstart事件

手指按下时,保存初始位置

_container.addEventListener("touchstart", function(e) {
 // e.preventDefault();//取消此行代码的注释会在该元素内阻止页面纵向滚动
 var touch = e.touches[0];
 startX = touch.clientX; //保存手指按下时的位置
 startY = touch.clientY;
 _container.style.webkitTransition = ""; //取消动画效果
 startT = new Date().getTime(); //记录手指按下的开始时间
 isMove = false;
 transitionItems(_prev, false); //取消之前元素的过渡
 transitionItems(_current, false); //取消当前元素的过渡
}, false);

touchmove事件

手指在屏幕上滑动,页面跟随手指移动

_container.addEventListener("touchmove", function(e) {
 // e.preventDefault();//取消此行代码的注释会在该元素内阻止页面纵向滚动
 var touch = e.touches[0];
 var deltaX = touch.clientX - startX; //计算手指在X方向滑动的距离
 var deltaY = touch.clientY - startY; //计算手指在Y方向滑动的距离
 //如果X方向上的位移大于Y方向,则认为是左右滑动
 if (Math.abs(deltaX) > Math.abs(deltaY)){
 translate = deltaX > _itemWidth ? _itemWidth : deltaX;
 translate = deltaX < -_itemWidth ? -_itemWidth : deltaX;

 //同时移动当前元素及其左右元素
 moveItems(translate); 

 isMove = true;
 }
}, false);

touchend事件

手指离开屏幕时,计算最终需要停留在哪一页

_container.addEventListener("touchend",function(e) {
 // e.preventDefault();//取消此行代码的注释会在该元素内阻止页面纵向滚动

 //是否会滚
 var isRollback = false;

 //计算手指在屏幕上停留的时间
 var deltaT = new Date().getTime() - startT;
 if (isMove) { //发生了左右滑动
 //如果停留时间小于300ms,则认为是快速滑动,无论滑动距离是多少,都停留到下一页
 if(deltaT < 300){
 translate = translate < 0 ? -_itemWidth : _itemWidth;
 }else {
 //如果滑动距离小于屏幕的50%,则退回到上一页
 if (Math.abs(translate) / _itemWidth < 0.5){
 isRollback = true;
 }else{
 //如果滑动距离大于屏幕的50%,则滑动到下一页
 translate = translate < 0 ? -_itemWidth : _itemWidth;
 }
 }

 moveTo(translate, isRollback);
 }
}, false);

Carousel库

为了方便使用,我将整个实现过程封装成了一个库,并添加了prev(), next()方法,使用非常简单:

<script src="lib/carousel.js"></script>

CreateCarousel("carousel", "item", true)
 .bindTouchEvent()
 .setItemChangedHandler(onPageChanged);

//参数"carousel"为容器的类名
//参数"item"为子元素的类名
//第三个参数设置是否需要循环播放,true为循环播放

下载本文
显示全文
专题