利用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 相关文章推荐
基于jsTree的无限级树JSON数据的转换代码
Jul 27 Javascript
40个有创意的jQuery图片和内容滑动及弹出插件收藏集之三
Jan 03 Javascript
jquery1.9 下检测浏览器类型和版本的方法
Dec 26 Javascript
JS数组去重与取重的示例代码
Jan 24 Javascript
无刷新上传文件并返回自定义值
Jun 11 Javascript
详解JavaScript的变量和数据类型
Nov 27 Javascript
基于Bootstrap使用jQuery实现输入框组input-group的添加与删除
May 03 Javascript
解析jQueryEasyUI的使用
Nov 22 Javascript
jquery获取下拉框中的循环值
Feb 08 Javascript
JavaScript实现图片无缝滚动效果
Jul 07 Javascript
Node.js创建一个Express服务的方法详解
Jan 06 Javascript
了不起的11个JavaScript代码重构最佳实践小结
Jan 11 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
PHP编程中八种常见的文件操作方式
2006/11/19 PHP
php把大写命名转换成下划线分割命名
2015/04/27 PHP
php通过curl添加cookie伪造登陆抓取数据的方法
2016/04/02 PHP
php实现转换html格式为文本格式的方法
2016/05/16 PHP
showModelessDialog()使用详解
2006/09/07 Javascript
javascript 解析后的xml对象的读取方法细解
2009/07/25 Javascript
silverlight线程与基于事件驱动javascript引擎(实现轨迹回放功能)
2011/08/09 Javascript
js data日期初始化的5种方法
2013/12/29 Javascript
Javascript中引用示例介绍
2014/02/21 Javascript
JavaScript生成二维码图片小结
2015/12/27 Javascript
解决微信内置浏览器返回上一页强制刷新问题方法
2017/02/05 Javascript
jQuery实现鼠标经过显示动画边框特效
2017/03/24 jQuery
详解微信小程序审核不通过的解决方法
2018/01/17 Javascript
JavaScript的数据类型转换原则(干货)
2018/03/15 Javascript
vue.extend实现alert模态框弹窗组件
2018/04/28 Javascript
JavaScript实现京东购物放大镜和选项卡效果的方法分析
2018/07/05 Javascript
Vuex 使用及简单实例(计数器)
2018/08/29 Javascript
JS实现百度网盘任意文件强制下载功能
2018/08/31 Javascript
vue.js+element-ui动态配置菜单的实例
2018/09/07 Javascript
解决LayUI数据表格复选框不居中显示的问题
2019/09/25 Javascript
vue实现全匹配搜索列表内容
2019/09/26 Javascript
详解JavaScript匿名函数和闭包
2020/07/10 Javascript
[48:12]Secret vs Optic Supermajor 胜者组 BO3 第三场 6.4
2018/06/05 DOTA
python原始套接字编程示例分享
2014/02/21 Python
python3之微信文章爬虫实例讲解
2017/07/12 Python
python-itchat 获取微信群用户信息的实例
2019/02/21 Python
python set内置函数的具体使用
2019/07/02 Python
Python-numpy实现灰度图像的分块和合并方式
2020/01/09 Python
Python 使用生成器代替线程的方法
2020/08/04 Python
Python函数__new__及__init__作用及区别解析
2020/08/31 Python
华为旗下电子商务平台:华为商城
2016/08/06 全球购物
2014年学校食堂工作总结
2014/11/25 职场文书
2014年小学数学工作总结
2014/12/12 职场文书
2016年教师节感言
2015/12/09 职场文书
营销策划分析:怎么策划才能更好销量产品?
2019/09/04 职场文书
Anaconda配置各版本Pytorch的实现
2021/08/07 Python