利用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 对象的定义方法
Jan 10 Javascript
javascript引用对象的方法
Jan 11 Javascript
用js实现键盘方向键翻页功能的代码
Jun 03 Javascript
jQuery的控件及事件(输入控件及回车事件)使用示例
Jul 25 Javascript
javascript数组遍历的方法实例分析
Sep 13 Javascript
两种简单的跨域方法(jsonp、php)
Jan 02 Javascript
浅谈Vue父子组件和非父子组件传值问题
Aug 22 Javascript
jquery实现侧边栏左右伸缩效果的示例
Dec 19 jQuery
jQuery实现列表的增加和删除功能
Jun 14 jQuery
微信小程序搭建自己的Https服务器
May 02 Javascript
判断js数据类型的函数实例详解
May 23 Javascript
jQuery实现简易聊天框
Feb 08 jQuery
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与已存在的Java应用程序集成
2006/10/09 PHP
zen_cart实现支付前生成订单的方法
2016/05/06 PHP
Yii2.0多文件上传实例说明
2017/07/24 PHP
PHP二维数组实现去除重复项的方法【保留各个键值】
2017/12/21 PHP
javascript实现动态CSS换肤技术的脚本
2007/06/29 Javascript
Jquery遍历节点的方法小集
2014/01/22 Javascript
jQuery多项选项卡的实现思路附样式及代码
2014/06/03 Javascript
javascript获取select值的方法分析
2015/07/02 Javascript
Bootstrap零基础学习第一课之模板
2016/07/18 Javascript
canvas实现爱心和彩虹雨效果
2017/03/09 Javascript
webpack4.x打包过程详解
2018/07/18 Javascript
jquery实现动态改变css样式的方法分析
2019/05/27 jQuery
在antd Form表单中select设置初始值操作
2020/11/02 Javascript
收集的几个Python小技巧分享
2014/11/22 Python
Python实现查看系统启动项功能示例
2018/05/10 Python
python实现小球弹跳效果
2019/05/10 Python
使用Python轻松完成垃圾分类(基于图像识别)
2019/07/09 Python
Python中url标签使用知识点总结
2020/01/16 Python
np.dot()函数的用法详解
2020/01/17 Python
浅谈tensorflow之内存暴涨问题
2020/02/05 Python
Python无头爬虫下载文件的实现
2020/04/02 Python
windows10在visual studio2019下配置使用openCV4.3.0
2020/07/14 Python
Python操作word文档插入图片和表格的实例演示
2020/10/25 Python
CK美国官网:Calvin Klein
2016/08/26 全球购物
布里斯班女装时尚品牌:Adrift
2017/12/28 全球购物
学生党员的自我评价范文
2014/03/01 职场文书
推荐信格式范文
2014/05/09 职场文书
离婚案件上诉状
2015/05/23 职场文书
辛德勒的名单观后感
2015/06/03 职场文书
离职证明范本
2015/06/12 职场文书
2015中学政教处工作总结
2015/07/22 职场文书
单位领导婚礼致辞
2015/07/28 职场文书
导游词之重庆渣滓洞
2020/01/08 职场文书
python3实现无权最短路径的方法
2021/05/12 Python
一文读懂navicat for mysql基础知识
2021/05/31 MySQL
el-table-column 内容不自动换行的解决方法
2022/08/14 Vue.js