利用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 有用的脚本函数
May 07 Javascript
基于jquery的实现简单的表格中增加或删除下一行
Aug 01 Javascript
Javascript中拼接大量字符串的方法
Feb 05 Javascript
Bootstrap3制作自己的导航栏
May 12 Javascript
bootstrap和jQuery.Gantt的css冲突 如何解决
May 29 Javascript
JavaScript 闭包详细介绍
Sep 28 Javascript
jQuery编写网页版2048小游戏
Jan 06 Javascript
常见的浏览器Hack技巧整理
Jun 29 Javascript
使用html+js+css 实现页面轮播图效果(实例讲解)
Sep 21 Javascript
Vue事件修饰符native、self示例详解
Jul 09 Javascript
layui form.render('select', 'test2') 更新渲染的方法
Sep 27 Javascript
js实现飞机大战游戏
Aug 26 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
Ajax PHP 边学边练 之三 数据库
2009/11/26 PHP
session在PHP大型web应用中的使用
2011/06/25 PHP
使用gd库实现php服务端图片裁剪和生成缩略图功能分享
2013/12/25 PHP
php修改指定文件后缀的方法
2014/09/11 PHP
分享精心挑选的23款美轮美奂的jQuery 图片特效插件
2012/08/14 Javascript
深入理解JavaScript 闭包究竟是什么
2013/04/12 Javascript
jquery获取自定义属性(attr和prop)实例介绍
2013/04/21 Javascript
ExtJS实现文件下载的方法实例
2013/11/09 Javascript
jQuery点击自身以外地方关闭弹出层的简单实例
2013/12/24 Javascript
利用BootStrap的Carousel.js实现轮播图动画效果
2016/12/21 Javascript
Javascript基础回顾之(二) js作用域
2017/01/31 Javascript
js css3实现图片拖拽效果
2017/03/04 Javascript
微信小程序商城项目之商品属性分类(4)
2017/04/17 Javascript
Vue2 使用 Echarts 创建图表实例代码
2017/05/18 Javascript
JavaScript之DOM_动力节点Java学院整理
2017/07/03 Javascript
Angular2生命周期钩子函数的详细介绍
2017/07/10 Javascript
基于Vue实例生命周期(全面解析)
2017/08/16 Javascript
深入研究React中setState源码
2017/11/17 Javascript
详解如何优雅地在React项目中使用Redux
2017/12/28 Javascript
javascript数据结构之多叉树经典操作示例【创建、添加、遍历、移除等】
2018/08/01 Javascript
vue相关配置文件详解及多环境配置详细步骤
2020/05/19 Javascript
[03:41]DOTA2上海特锦赛小组赛第三日recap精彩回顾
2016/02/28 DOTA
python脚本设置超时机制系统时间的方法
2016/02/21 Python
使用Python &amp; Flask 实现RESTful Web API的实例
2017/09/19 Python
python利用rsa库做公钥解密的方法教程
2017/12/10 Python
python如何为被装饰的函数保留元数据
2018/03/21 Python
pytorch构建网络模型的4种方法
2018/04/13 Python
Python 统计字数的思路详解
2018/05/08 Python
python机器学习实现决策树
2019/11/11 Python
python读取多层嵌套文件夹中的文件实例
2020/02/27 Python
TecoBuy澳大利亚:在线电子和小工具商店
2020/06/25 全球购物
Hashtable 添加内容的方式有哪几种,有什么区别?
2012/04/08 面试题
护士演讲稿范文
2014/01/05 职场文书
实习公司领导推荐函
2014/05/21 职场文书
反对邪教标语
2014/06/30 职场文书
2016母亲节感恩话语
2015/12/09 职场文书