利用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 高效运行代码分析
Mar 18 Javascript
jQuery下通过replace字符串替换实现大小图片切换
May 22 Javascript
javaScript array(数组)使用字符串作为数组下标的方法
Nov 19 Javascript
js文本框输入点回车触发确定兼容IE、FF等
Nov 19 Javascript
JavaScript实现的encode64加密算法实例分析
Apr 15 Javascript
javascript淘宝主图放大镜功能
Oct 20 Javascript
常用的几个JQuery代码片段
Mar 13 Javascript
EasyUI Tree树组件无限循环的解决方法
Sep 27 Javascript
Vue项目全局配置微信分享思路详解
May 04 Javascript
JS双向链表实现与使用方法示例(增加一个previous属性实现)
Jan 31 Javascript
用VueJS写一个Chrome浏览器插件的实现方法
Feb 27 Javascript
js 将线性数据转为树形的示例代码
May 28 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/10/09 PHP
php缩放图片(根据宽高的等比例缩放)实例介绍
2013/06/09 PHP
php数组添加与删除单元的常用函数实例分析
2015/02/16 PHP
Zend Framework框架实现类似Google搜索分页效果
2016/11/25 PHP
php使用str_shuffle()函数生成随机字符串的方法分析
2017/02/17 PHP
PHP 对象接口简单实现方法示例
2020/04/13 PHP
PHP 实现 JSON 数据的编码和解码操作详解
2020/04/22 PHP
jQueryUI如何自定义组件实现代码
2010/11/14 Javascript
jQuery源码解读之hasClass()方法分析
2015/02/20 Javascript
推荐10 个很棒的 jQuery 特效代码
2015/10/04 Javascript
jQuery利用sort对DOM元素进行排序操作
2016/11/07 Javascript
原生JS+Canvas实现五子棋游戏
2020/05/28 Javascript
vue 组件的封装之基于axios的ajax请求方法
2018/08/11 Javascript
微信小程序实现bindtap等事件传参
2019/04/08 Javascript
javascript实现fetch请求返回的统一拦截
2019/12/22 Javascript
使用Python读取二进制文件的实例讲解
2018/07/09 Python
python实现泊松图像融合
2018/07/26 Python
10分钟教你用Python实现微信自动回复功能
2018/11/28 Python
对python实现二维函数高次拟合的示例详解
2018/12/29 Python
python解析xml文件方式(解析、更新、写入)
2020/03/05 Python
python爬虫请求头设置代码
2020/07/28 Python
解决PyCharm无法使用lxml库的问题(图解)
2020/12/22 Python
HTML+CSS3模拟心的跳动实例代码
2017/09/05 HTML / CSS
Darphin迪梵官网: 来自巴黎,植物和精油调制的护肤品牌
2016/10/11 全球购物
英国的一家创新礼品和小工具零售商:Menkind
2019/08/24 全球购物
传媒专业推荐信范文
2013/11/23 职场文书
中学生个人自我评价
2014/02/06 职场文书
金融事务专业求职信
2014/04/25 职场文书
竞选大队长演讲稿
2014/04/29 职场文书
岗位说明书标准范本
2014/07/30 职场文书
四风问题原因分析及整改措施
2014/10/24 职场文书
2015年乡镇扶贫工作总结
2015/04/08 职场文书
2015年初中教务处工作总结
2015/07/21 职场文书
财产分割协议书
2016/03/22 职场文书
同学联谊会邀请函
2019/06/24 职场文书
人事部:年度述职报告范文
2019/07/12 职场文书