利用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 相关文章推荐
原生js实现半透明遮罩层效果具体代码
Jun 06 Javascript
Javascript递归打印Document层次关系实例分析
May 15 Javascript
jQuery实现仿腾讯视频列表分页效果的方法
Aug 07 Javascript
Bootstrap每天必学之导航条
Nov 27 Javascript
jQuery绑定事件-多种实现方式总结
May 09 Javascript
可输入文字查找ajax下拉框控件 ComBox的实现方法
Oct 25 Javascript
简单的网页广告特效实例
Aug 19 Javascript
ES6 对象的新功能与解构赋值介绍
Feb 05 Javascript
使用Vue实现简单计算器
Feb 25 Javascript
vue中渲染对象中属性时显示未定义的解决
Jul 31 Javascript
Vue使用鼠标在Canvas上绘制矩形
Dec 24 Vue.js
vue递归实现树形组件
Jul 15 Vue.js
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实现用户在线时间统计详解
2011/10/08 PHP
php array的学习笔记
2012/05/16 PHP
解析file_get_contents模仿浏览器头(user_agent)获取数据
2013/06/27 PHP
PHP实现WebService的简单示例和实现步骤
2015/03/27 PHP
PHP永久登录、记住我功能实现方法和安全做法
2015/04/27 PHP
php集成开发环境详解
2019/09/24 PHP
js判断两个日期是否相等的方法
2013/09/10 Javascript
javascript模拟枚举的简单实例
2014/03/06 Javascript
JavaScript分页功能的实现方法
2015/04/25 Javascript
javascript中Date format(js日期格式化)方法小结
2015/12/17 Javascript
jQuery Ajax Post 回调函数不执行问题的解决方法
2016/08/15 Javascript
用Angular实时获取本地Localstorage数据,实现一个模拟后台数据登入的效果
2016/11/09 Javascript
Javascript Event(事件)的传播与冒泡
2017/01/23 Javascript
JS实现的tab切换选项卡效果示例
2017/02/28 Javascript
JS实现的二叉树算法完整实例
2017/04/06 Javascript
使用jquery DataTable和ajax向页面显示数据列表的方法
2018/08/09 jQuery
Layer弹出层动态获取数据的方法
2018/08/20 Javascript
Vue.js中 v-model 指令的修饰符详解
2018/12/03 Javascript
仿ElementUI实现一个Form表单的实现代码
2019/04/23 Javascript
Python迭代用法实例教程
2014/09/08 Python
利用python画一颗心的方法示例
2017/01/31 Python
基于Python os模块常用命令介绍
2017/11/03 Python
对Python3 序列解包详解
2019/02/16 Python
python pandas 时间日期的处理实现
2019/07/30 Python
python正则表达式的懒惰匹配和贪婪匹配说明
2020/07/13 Python
纽约JewelryAffairs珠宝店:精细金银时尚首饰
2017/02/05 全球购物
海滩咖啡馆:Beach Cafe
2018/02/02 全球购物
Groupon比利时官方网站:特卖和网上购物高达-70%
2019/08/09 全球购物
Footshop乌克兰:运动鞋的最大选择
2019/12/01 全球购物
统计员岗位职责
2013/11/14 职场文书
我的大学生活职业生涯规划
2014/01/02 职场文书
2014自主招生自荐信策略
2014/01/27 职场文书
学雷锋活动总结范文
2014/04/25 职场文书
室内趣味活动方案
2014/08/24 职场文书
建房合同协议书
2016/03/21 职场文书
星际争霸:毕姥爷vs解冻03
2022/04/01 星际争霸