利用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 原型继承
Dec 26 Javascript
jQuery-Tools-overlay 使用介绍
Jul 14 Javascript
jQuery固定浮动侧边栏实现思路及代码
Sep 28 Javascript
详解Vue.js——60分钟组件快速入门(上篇)
Dec 05 Javascript
jQuery animate()实现背景色渐变效果的处理方法【使用jQuery.color.js插件】
Mar 15 Javascript
JS判断Android、iOS或浏览器的多种方法(四种方法)
Jun 29 Javascript
浅谈Node.js ORM框架Sequlize之表间关系
Jul 24 Javascript
JS中的JSON对象的定义和取值实现代码
May 09 Javascript
vscode中vue-cli项目es-lint的配置方法
Jul 30 Javascript
vue-cli 脚手架基于Nightwatch的端到端测试环境的过程
Sep 30 Javascript
Vue移动端右滑屏幕返回上一页附源码下载
Jun 26 Javascript
详解将微信小程序接口Promise化并使用async函数
Aug 05 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中的Session和Cookie
2013/06/21 PHP
PHP命名空间(namespace)原理与用法详解
2019/12/11 PHP
将HTMLCollection/NodeList/伪数组转换成数组的实现方法
2011/06/20 Javascript
javascript中创建对象的几种方法总结
2013/11/01 Javascript
js判断iframe内的网页是否滚动到底部触发事件
2014/03/18 Javascript
jQuery仿天猫实现超炫的加入购物车
2015/05/04 Javascript
AngularJS基础学习笔记之控制器
2015/05/10 Javascript
IE浏览器下PNG相关功能
2015/07/05 Javascript
日常收集整理的JavaScript常用函数方法
2015/12/10 Javascript
AngualrJS中每次$http请求时的一个遮罩层Directive
2016/01/26 Javascript
javascript html5摇一摇功能的实现
2016/04/19 Javascript
bootstrap布局中input输入框右侧图标点击功能
2016/05/16 Javascript
Vue.js每天必学之过滤器与自定义过滤器
2016/09/07 Javascript
JavaScript 中 apply 、call 的详解
2017/03/21 Javascript
ES6中Generator与异步操作实例分析
2017/03/31 Javascript
ionic+AngularJs实现获取验证码倒计时按钮
2017/04/22 Javascript
vue.js todolist实现代码
2017/10/29 Javascript
弱类型语言javascript开发中的一些坑实例小结【变量、函数、数组、对象、作用域等】
2019/08/07 Javascript
vue中beforeRouteLeave实现页面回退不刷新的示例代码
2019/11/01 Javascript
详解react组件通讯方式(多种)
2020/05/06 Javascript
EXTJS7实现点击拖拉选择文本
2020/12/17 Javascript
[50:59]2018DOTA2亚洲邀请赛 4.7 总决赛 LGD vs Mineski第四场
2018/04/10 DOTA
Python可变参数*args和**kwargs用法实例小结
2018/04/27 Python
扩展Django admin的list_filter()可使用范围方法
2019/08/21 Python
Python图像处理库PIL的ImageFont模块使用介绍
2020/02/26 Python
基于HTML5新特性Mutation Observer实现编辑器的撤销和回退操作
2016/01/11 HTML / CSS
Scholastic父母商店:儿童书籍
2017/01/01 全球购物
c语言常见笔试题总结
2016/09/05 面试题
职业生涯规划书基本格式
2014/01/06 职场文书
大学生社团活动总结
2014/04/26 职场文书
委托书如何写
2014/08/30 职场文书
MySql新手入门的基本操作汇总
2021/05/13 MySQL
详解PHP用mb_string处理windows中文字符
2021/05/26 PHP
使用Python的开发框架Brownie部署以太坊智能合约
2021/05/28 Python
Pytorch中Softmax和LogSoftmax的使用详解
2021/06/05 Python
MySQL的全局锁和表级锁的具体使用
2021/08/23 MySQL