利用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 06 Javascript
Javascript insertAfter() 实现函数代码
Oct 12 Javascript
js中Math之random,round,ceil,floor的用法总结
Dec 26 Javascript
JS实现把鼠标放到链接上出现滚动文字的方法
Apr 06 Javascript
JS模拟的Map类实现方法
Jun 17 Javascript
jQuery实现的导航下拉菜单效果示例
Sep 05 Javascript
微信小程序中单位rpx和rem的使用
Dec 06 Javascript
JS实现小球的弹性碰撞效果
Nov 11 Javascript
详解使用VUE搭建后台管理系统(vue-cli更新至3.0)
Aug 22 Javascript
vue把输入框的内容添加到页面的实例讲解
Nov 11 Javascript
vue-resource 拦截器interceptors使用详解
Jan 18 Vue.js
正则表达式基础与常用验证表达式
Jun 16 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 的ArrayAccess接口 像数组一样来访问你的PHP对象
2010/10/12 PHP
多浏览器支持的右下角浮动窗口
2010/04/01 Javascript
jQuery表单验证插件formValidator(改进版)
2012/02/03 Javascript
关于js注册事件的常用方法
2013/04/03 Javascript
JS性能优化笔记搜索整理
2013/08/21 Javascript
jquery属性选择器not has怎么写 行悬停高亮显示
2013/11/13 Javascript
原生javascript实现Tab选项卡切换功能
2015/01/12 Javascript
Nodejs学习笔记之Stream模块
2015/01/13 NodeJs
jQuery插件Tooltipster实现漂亮的工具提示
2015/04/12 Javascript
JavaScript 实现完美兼容多浏览器的复制功能代码
2015/04/28 Javascript
Ztree新增角色和编辑角色回显问题的解决
2016/10/25 Javascript
扩展jquery easyui tree的搜索树节点方法(推荐)
2016/10/28 Javascript
javascript 实现文本使用省略号替代(超出固定高度的情况)
2017/02/21 Javascript
karma+webpack搭建vue单元测试环境的方法示例
2018/05/24 Javascript
微信小程序实现手势滑动卡片效果
2019/08/26 Javascript
Vue Render函数原理及代码实例解析
2020/07/30 Javascript
python算法学习之桶排序算法实例(分块排序)
2013/12/18 Python
Python中类的继承代码实例
2014/10/28 Python
Python 的 Socket 编程
2015/03/24 Python
Python常用随机数与随机字符串方法实例
2015/04/09 Python
在Python中使用全局日志时需要注意的问题
2015/05/06 Python
详解Python中的元组与逻辑运算符
2015/10/13 Python
python使用wxpy轻松实现微信防撤回的方法
2019/02/21 Python
Python中常用的高阶函数实例详解
2020/02/21 Python
解决keras模型保存h5文件提示无此目录问题
2020/07/01 Python
10分钟理解CSS3 Grid布局
2018/12/20 HTML / CSS
检测浏览器是否支持html5视频的代码
2013/03/28 HTML / CSS
中学生在校期间的自我评价分享
2013/11/13 职场文书
广告业务员岗位职责
2014/02/06 职场文书
电子商务系毕业生自荐信
2014/05/29 职场文书
大学社团招新的通讯稿
2014/09/10 职场文书
2015年加油站站长工作总结
2015/05/27 职场文书
少年派的奇幻漂流观后感
2015/06/08 职场文书
致运动员的广播稿
2015/08/19 职场文书
Go 通过结构struct实现接口interface的问题
2021/10/05 Golang
Rust中的Struct使用示例详解
2022/08/14 Javascript