JavaScript   发布时间:2022-04-16  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了移动端效果之Swiper详解大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

写在前面

最近在做移动端方面运用到了饿了么的vue前端组件库,因为不想单纯用组件而使用它,故想深入了解一下实现原理。后续将会继续研究一下其他的组件实现原理,有兴趣的可以关注下。

移动端效果之Swiper详解

代码在这里:https://jsbin.com/koriguy/2/edit?js">戳我

1. 说明

父容器);width:100%;

2. 核心解析

2.1 页面初始化

由于所有页面都在手机屏幕左侧一个屏幕宽度的位置,因此最开始的情况是页面中看不到任何一个子页面,所以第一步应该设置应该显示的子页面,默认情况下Tindex:0

{ // 得出页面是否能够被滑动 // 1. 子页面只有一个 // 2. 用户手动设置不能滑动 noDragWhenSingle = true noDrag = children.length === 1 && noDragWhenSingle;

var aPages = [];
var intDefaulTindex = Math.floor(defaulTindeX);
var defaulTindex = (intDefaulTindex >= 0 && intDefaulTindex < children.length)
? intDefaulTindex : 0;

// 得到当前被激活的子页面索引
index = defaulTindex;

children.forEach(function(child,indeX) {
aPages.push(child);
// 所有页面移除激活class
child.classList.remove('is-active');

if (index === defaulTindeX) {
  // 给激活的子页面加上激活class
  child.classList.add('is-active');
}

});

pages = aPages;
}

2.2 容器滑动开始(onTouchStart)

在低版本的

前置工作:

  • 如果用户设置了 prevent:true, 滑动时阻止默认行为
  • 如果用户设置了stopPropagation:true, 滑动时阻止事件向上传播
  • 如果动画尚未结束,阻止滑动
  • 设置dragging:true,滑动开始
  • 设置用户滚动为false

滑动开始:

使用一个全局对象记录信息,这些信息包括:

{ startTime // 开始时间 startLeft // 开始的X坐标 startTop // 开始的Y坐标(相对于整个页面viewport pageY) startTopAbsolute // 绝对Y坐标(相对于文档顶部 clientY) pageWidth // 一个页面宽度 pageHeight // 一个页面的高度 prevPage // 上一个页面 dragPage // 当前页面 nextPage // 下一个页面 };

2.3 容器滑动(onTouchMovE)

套用全局

{ currentLeft // 开始的X坐标 currentTop // 开始的Y坐标(相对于整个页面viewport pageY) currentTopAbsolute // 绝对Y坐标(相对于文档顶部 clientY) };

那么我们就可以通过开始和滑动中的信息来计算出一些东西:

滑动的水平位移(offsetLeft = currentLeft - startLeft)

滑动的垂直位移(offsetTop = currentTopAbsolute - startTopAbsolute)

是否是用户的自然滚动,这里的自然滚动说的是用户并不是想滑动swiper,而是想滑动页面

); // distanceY = Math.abs(offsetTop); distanceX < 5 || ( distanceY >= 5 && distanceY >= 1.73 * distanceX )

判断是左移还是右移(offsetLeft < 0 左移,反之,右移)

重置位移

0 // 那么也就是说 offsetLeft - dragState.pageWidth 的值一直在变大,但是仍未负数 // 这就是为什么当连续属性存在的时候左滑会看到上一个页面会跟着滑动的原因 // 这里的 translate 方法其实很简单,在滑动的时候去除了动画效果`transition`,单纯改变位移 // 而在滑动结束的时候,加上`transition`,使得滑动到最后释放的过渡更加自然 translate(dragState.prevPage,offsetLeft - dragState.pageWidth); }

// 当前页面跟着滑动
translate(dragState.dragPage,offsetLeft);

// 后一个页面同理
if (dragState.nextPage && toWARDs === 'next') {
translate(dragState.nextPage,offsetLeft + dragState.pageWidth);
}

2.4 滑动结束(onTouchEnd)

前置工作:

在滑动中,我们是可以实时地来判断到底是不是用户的自然滚动userScrolling,如果是用户自然滚动,那么

false; dragState = {};

当然如果userScrolling:false,那么就是滑动子页面,执行doOnTouchEnd方法

判断是否是tap事件

{ var fireTap = Math.abs(offsetLeft) < 5 && Math.abs(offsetTop < 5); if (isNaN(offsetLeft) || isNaN(offsetTop)) { fireTap = true; } if (fireTap) { console.log('tap'); } }

判断方向

// 如果事件间隔小于300ms 或者 滑动位移超过屏幕宽度 1/2, 根据位移判断方向
if (dragDuration < 300 || Math.abs(offsetLeft) > pageWidth / 2) {
toWARDs = offsetLeft < 0 ? 'next' : 'prev';
}

// 如果非连续,当处于第一页,不会出现上一页,当处于最后一页,不会出现下一页
if (!conTinuous) {
if ((index === 0 && toWARDs === 'prev')
|| (index === PageCount - 1 && toWARDs === 'next')) {
toWARDs = null;
}
}

// 子页面数量小于2时,不执行滑动动画
if (children.length < 2) {
toWARDs = null;
}

执行动画

<div class="jb51code">
<pre class="brush:js;">
// 当没有options的时候,为自然滑动,也就是定时器滑动
function doAnimate(toWARDs,options) {
if (children.length === 0) return;
if (!options && children.length < 2) return;

var prevPage,nextPage,currentPage,pageWidth,offsetLeft;
var PageCount = pages.length;

// 定时器滑动
if (!options) {
pageWidth = element.clientWidth;
currentPage = pages[index];
prevPage = pages[index - 1];
nextPage = pages[index + 1];
if (conTinuous && pages.length > 1) {
if (!prevPagE) {
prevPage = pages[pages.length - 1];
}

  if (!nextPagE) {
    nextPage = pages[0];
  }
}

// 计算上一页与下一页之后
// 重置位移
// 参看doOnTouchMove
// 其实这里的options 传与不传也就是获取上一页信息与下一页信息
if (prevPagE) {
  prevPage.style.display = 'block';
  translate(prevPage,-pageWidth);
}

if (nextPagE) {
  nextPage.style.display = 'block';
  translate(nextPage,pageWidth);
}

} else {
prevPage = options.prevPage;
currentPage = options.currentPage;
nextPage = options.nextPage;
pageWidth = options.pageWidth;
offsetLeft = options.offsetLeft;
}

var newIndex;
var oldPage = children[index];

// 得到滑动之后的新的索引
if (toWARDs === 'prev') {
if (index > 0) {
newIndex = index - 1;
}
if (conTinuous && index === 0) {
newIndex = PageCount - 1;
}
} else if (toWARDs === 'next') {
if (index < PageCount - 1) {
newIndex = index + 1;
}
if (conTinuous && index === PageCount - 1) {
newIndex = 0;
}
}

// 动画完成之后的回调
var callBACk = function() {
// 得到滑动之后的激活页面,添加激活class
// 重新赋值索引
if (newIndex !== undefined) {
var newPage = children[newIndex];
oldPage.classList.remove('is-active');
newPage.classList.add('is-active');
index = newIndex
}

if (isDonE) {
  end();
}

if (prevPagE) {
  prevPage.style.display = '';
}

if (nextPagE) {
  nextPage.style.display = '';
}

}

setTimeout(function() {
// 向后滑动
if (toWARDs === 'next') {
isDone = true;
before(currentPagE);
// 当前页执行动画,完成后执行callBACk
translate(currentPage,-pageWidth,speed,callBACk);
if (nextPagE) {
// 下一面移动视野中
translate(nextPage,speed)
}
} else if (toWARDs === 'prev') {
isDone = true;
before(currentPagE);
translate(currentPage,callBACk);
if (prevPagE) {
translate(prevPage,speed);
}
} else {
// 如果既不是左滑也不是右滑
isDone = true;
// 当前页面依旧处于视野中
// 上一页和下一页滑出
translate(currentPage,callBACk);
if (typeof offsetLeft !== 'undefined') {
if (prevPage && offsetLeft > 0) {
translate(prevPage,pageWidth * -1,speed);
}
if (nextPage && offsetLeft < 0) {
translate(nextPage,speed);
}
} else {
if (prevPagE) {
translate(prevPage,speed);
}

  if (nextPagE) {
   translate(nextPage,speed);
  }
 }
}

},10);
}

后置工作:

清除一次滑动周期中保存的状态信息

false; dragState = {};

总结

整体来说实现原理还是比较简单的,滑动开始记录初始位置,计算上一页与下一页的应该展示的页面;滑动中计算位移,计算上一页下一页的位移;滑动结束根据位移结果执行相应的动画。

有一个细节就是,在滑动中

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持菜鸟教程。

大佬总结

以上是大佬教程为你收集整理的移动端效果之Swiper详解全部内容,希望文章能够帮你解决移动端效果之Swiper详解所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签:移动端