利用JS实现scroll自定义滚动效果详解


Posted in Javascript onOctober 17, 2017

前言

最近在公司开发项目的时候,原生滚动条中有些东西没办法自定义去精细的控制,于是开发一个类似于better-scroll一样的浏览器滚动监听的JS实现,下面我们就来探究一下自定义滚动需要考虑哪些东西,经过哪些过程。话不多说了,来一起看看详细的介绍吧。

选择滚动监听的事件

因为是自定义手机端的滚动事件,那我选择的是监听手机端的三个touch事件来实现监听,并实现了两种滚动效果,一种是通过-webkit-transform,一种是通过top属性。两种实现对于滚动的基本效果够能达到,可是top的不适合滚动中还存在滚动,可是能解决滚动中存在postion:fixed属性的问题;而transform可以实现滚动中有滚动,可是又不能解决postion:fixed的问题,所以,最后选择性考虑使用哪一种实现方式,用法一样。

主要的实现业务逻辑

handleTouchMove(event){
 event.preventDefault();
 this.currentY = event.targetTouches[0].screenY;
 this.currentTime = new Date().getTime();
 // 二次及以上次数滚动(间歇性滚动)时间和路程重置计算,0.05是间歇性滚动的停顿位移和时间比
 if (Math.abs(this.currentY - this.lastY) / Math.abs(this.currentTime - this.lastTime) < 0.05) {
  this.startTime = new Date().getTime();
  this.resetY = this.currentY;
 }
 this.distance = this.currentY - this.startY;
 let temDis = this.distance + this.oldY;
 /*设置移动最小值*/
 temDis = temDis > this.minValue ? temDis * 1 / 3 : temDis;
 /*设置移动最大值*/
 temDis = temDis < -this.maxValue ? -this.maxValue + (temDis + this.maxValue) * 1 / 3 : temDis;
 this.$el.style["top"] = temDis + 'px';
 this.lastY = this.currentY;
 this.lastTime = this.currentTime;
 this.dispatchEvent();
 this.scrollFunc(event);
},

代码解读:这是监听touchmove事件的回调,其中主要计算出目标节点this.$el的top或者-webkit-transform中translateY的值,而计算的参考主要以事件节点的screenY的垂直移动距离为参考,当然其中还要判断一下最大值和最小值,为了保证移动可以的超出最大值小值一定的距离所以加了一个1/3的移动计算。这里可能主要到了有一个间歇性滚动的判断和计算,主要是服务于惯性滚动的,目的是让惯性滚动的值更加精确。

handleTouchEnd(event){
 /*点透事件允许通过*/
 if (!this.distance) return;
 event.preventDefault();
 let temDis = this.distance + this.oldY;
 /*计算缓动值*/
 temDis = this.computeSlowMotion(temDis);
 /*设置最小值*/
 temDis = temDis > this.minValue ? this.minValue : temDis;
 /*设置最大值*/
 temDis = temDis < -this.maxValue ? -this.maxValue : temDis;
 this.$el.style["transitionDuration"] = '500ms';
 this.$el.style["transitionTimingFunction"] = 'ease-out';
 /*确定最终的滚动位置*/
 setTimeout(()=> {
  this.$el.style["top"] = temDis + 'px';
 }, 0);
 // 判断使用哪一种监听事件
 if (this.slowMotionFlag) {
  this.dispatchEventLoop();
 } else {
  this.dispatchEvent();
 }
 this.$el.addEventListener('transitionend', ()=> {
  window.cancelAnimationFrame(this.timer);
 });
 this.scrollFunc(event);
}

代码解读:这是touchend事件监听的回调,其中这里要判断是否要拦截click和tap事件,并且这里还要计算惯性缓动值,设置最终的最大最小值,以及设置动画效果和缓动效果。下面来谈一下滚性滚动的计算:

// 计算惯性滚动值
computeSlowMotion(temDis){
 var duration = new Date().getTime() - this.startTime;
 // 300毫秒是判断间隔的最佳时间
 var resetDistance = this.currentY - this.resetY;
 if (duration < 300 && Math.abs(resetDistance) > 10) {
  var speed = Math.abs(resetDistance) / duration,
   destination;
  // 末速度为0 距离等于初速度的平方除以2倍加速度
  destination = (speed * speed) / (2 * this.deceleration) * (resetDistance < 0 ? -1 : 1);
  this.slowMotionFlag = true;
  return temDis += destination;
 } else {
  this.slowMotionFlag = false;
  return temDis;
 }
},

代码解读:滚性滚动的算法主要是根据一个路程和时间计算出初速度,以及原生滚动的加速度的大于值0.006来计算滚动的总位移。这里主要还要判断一下一个300ms的经验值。

总结

大概的流程和思考就是这样了,后续还会增加更多的功能进行扩展

附上git地址:https://github.com/yejiaming/scroll

本地下载:http://xiazai.3water.com/201710/yuanma/js-scroll-custom(3water.com).rar

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

Javascript 相关文章推荐
JavaScript 指导方针
Apr 05 Javascript
web页面数据展示新想法(json)
Jun 08 Javascript
jQuery插件原来如此简单 jQuery插件的机制及实战
Feb 07 Javascript
Javascript 绘制 sin 曲线过程附图
Aug 21 Javascript
网页瀑布流布局jQuery实现代码
Oct 21 Javascript
JS实现的加减乘除四则运算计算器示例
Aug 09 Javascript
详解A标签中href=&quot;&quot;的几种用法
Aug 20 Javascript
JavaScript中callee和caller的区别与用法实例分析
Jun 28 Javascript
js通过循环多张图片实现动画效果
Dec 19 Javascript
解决angular 使用原生拖拽页面卡顿及表单控件输入延迟问题
Apr 21 Javascript
Openlayers绘制聚合标注
Sep 28 Javascript
JS前端轻量fabric.js系列物体基类
Aug 05 Javascript
jquery实现图片跟随鼠标的实例
Oct 17 #jQuery
vue获取input输入值的问题解决办法
Oct 17 #Javascript
node.js 用socket实现聊天的示例代码
Oct 17 #Javascript
Bootstrap图片轮播效果详解
Oct 17 #Javascript
vue组件之Alert的实现代码
Oct 17 #Javascript
JS实现按钮添加背景音乐示例代码
Oct 17 #Javascript
vue-cli之router基本使用方法详解
Oct 17 #Javascript
You might like
php5.2.0内存管理改进
2007/01/22 PHP
学习php过程中的一些注意点的总结
2013/10/25 PHP
Yii2.0中的COOKIE和SESSION用法
2016/08/12 PHP
PHP排序算法之直接插入排序(Straight Insertion Sort)实例分析
2018/04/20 PHP
JavaScript 变量基础知识
2009/11/07 Javascript
jquery 事件执行检测代码
2009/12/09 Javascript
php对mongodb的扩展(小试牛刀)
2012/11/11 Javascript
javascript如何判断输入的url是否正确
2014/04/11 Javascript
在浏览器中实现图片粘贴的jQuery插件-- pasteimg使用指南
2014/12/29 Javascript
使用jquery+CSS实现控制打印样式
2014/12/31 Javascript
z-blog SyntaxHighlighter 长代码无法换行解决办法(基于jquery)
2015/11/18 Javascript
详解微信小程序Radio选中样式切换
2017/07/06 Javascript
浅谈关于angularJs中使用$.ajax的注意点
2017/08/12 Javascript
在vue中封装可复用的组件方法
2018/03/01 Javascript
jQuery中的$是什么意思及 $. 和 $().的区别
2018/04/20 jQuery
angularJs中orderBy筛选以及filter过滤数据的方法
2018/09/30 Javascript
jquery层次选择器的介绍
2019/01/18 jQuery
Layui Form 自定义验证的实例代码
2019/09/14 Javascript
解决layui的form里的元素进行动态生成,验证失效的问题
2019/09/14 Javascript
详解JavaScript数据类型和判断方法
2020/09/04 Javascript
Python下调用Linux的Shell命令的方法
2018/06/12 Python
浅谈python的dataframe与series的创建方法
2018/11/12 Python
在Python中构建增广矩阵的实现方法
2019/07/01 Python
详解一种用django_cache实现分布式锁的方式
2019/09/01 Python
加拿大购物频道:The Shopping Channel
2016/07/21 全球购物
全球领先的美容用品专卖店:Beauty Plus Salon
2018/09/04 全球购物
澳大利亚波希米亚风时尚品牌:Tree of Life
2019/09/15 全球购物
精伦电子Java笔试题
2013/01/16 面试题
EJB的角色和三个对象
2015/12/31 面试题
毕业生找工作的自我评价
2013/10/18 职场文书
教师辞职报告范文
2014/01/20 职场文书
局火灾防控工作方案
2014/05/25 职场文书
新法人代表任命书
2014/06/06 职场文书
学习三严三实对照检查材料思想汇报
2014/09/22 职场文书
2014向国旗敬礼网上签名活动总结
2014/09/27 职场文书
2014年安置帮教工作总结
2014/12/11 职场文书