手机惯性滚动时应该怎么计算速度,以及之后速度怎么递减等问题

因为要做一个手机端的滚动插件,所以想模拟出手机原生的惯性滚动,就是手指快速滑动后,手机页面在手指抬起来之后,依然会滚动一段距离的效果。

现在我尝试了两种方法

1、在手指start与end之间时间少于300ms时,根据手指移动距离得出需要继续滚动的长度,在end之后通过transition与top实现动画效果

2、在手指end之后通过手指的移动距离与使用时间计算平局速度,如果使用时间少于300ms,则通过requestAnimationFrame循环调用一个每次都递减速度的函数,当速度很小时跳出函数循环。在函数中每一次都设置一次top值,因为requestAnimationFrame间隔很短,大概之后16ms左右,以实现效果

第一种方法代码

移动手指事件滚动

* {

margin: 0;

padding: 0;

}

.container {

position: relative;

margin: 50px;

width: calc(100% - 100px);

height: 400px;

border: 1px solid green;

box-sizing: border-box;

overflow: hidden;

}

.container .scroll {

position: absolute;

top: 0;

left: 0;

width: 100%;

transition: all 160ms ease-out;

}

.container p {

margin: 0 auto 10px;

width: 80%;

height: 80px;

border: 1px solid yellow;

}

.container .scroll:after {

content: '';

display: block;

clear: both;

}

.container .barBox {

position: absolute;

right: 2px;

top: 2px;

width: 3px;

height: calc(100% - 4px);

background: rgba(100, 200, 100, 0.3);

}

.container .barBox .bar {

position: absolute;

top: 0;

right: 0;

height: 0;

width: 100%;

background: #ccc;

transition: all 160ms ease-out;

}

var oContainer = document.getElementById('container');

var oScroll = oContainer.children[0];

var oBarBox = document.getElementById('barBox');

var oBar = oBarBox.children[0];

// 盒子尺寸

var iWrapperH = numberPx(getStyle(oContainer, 'height'));

var iScrollH = numberPx(getStyle(oScroll, 'height'));

var iBarBoxH = numberPx(getStyle(oBarBox, 'height'));

var iBarH = iWrapperH / iScrollH * iBarBoxH;

// 初始状态

setStyle(oBar, {

height: iBarH + 'px'

})

// 参数

var startTime = 0;

var endTime = 0;

var isMove = false;

var iScrollTop = 0;

var iBarTop = 0;

var endTimeout = null;

oContainer.addEventListener('touchstart', function (e) {

startTime = new Date().getTime();

var startY = e.targetTouches[0].clientY;

var startTop = numberPx(getStyle(oScroll, 'top'));

var endY = startY;

var endTop = startTop;

setStyle(oScroll, {

top: startTop + 'px'

})

setStyle(oBar, {

top: -startTop / iScrollH * iBarBoxH + 'px'

})

var moveFn = function (e) {

isMove = true;

var nowY = e.targetTouches[0].clientY;

var nowTop = startTop;

endY = nowY;

var moveY = nowY - startY;

nowTop += moveY;

endTop = nowTop;

iScrollTop = nowTop > 0 ? 0 : (nowTop < iWrapperH - iScrollH ? iWrapperH - iScrollH : nowTop);

iBarTop = -iScrollTop / iScrollH * iBarBoxH;

setStyle(oScroll, {

top: iScrollTop + 'px'

})

setStyle(oBar, {

top: iBarTop + 'px'

})

}

var endFn = function (e) {

endTime = new Date().getTime();

if ( endTime - startTime <= 200 && isMove ) {

var moveY = endY - startY;

var iScale = 1;

var iTime = 300;

if ( Math.abs(moveY) <= 100 ) {

iScale = 1;

iTime = 300;

} else if ( Math.abs(moveY) <= 200 ) {

iScale = 2;

iTime = 500;

} else {

iScale = 3;

iTime = 700;

}

moveY = moveY * iScale;

endTop += moveY;

iScrollTop = endTop > 0 ? 0 : (endTop < iWrapperH - iScrollH ? iWrapperH - iScrollH : endTop);

iBarTop = -iScrollTop / iScrollH * iBarBoxH;

setStyle(oScroll, {

transition: 'all ' + iTime + 'ms ease-out',

top: iScrollTop + 'px'

})

setStyle(oBar, {

transition: 'all ' + iTime + 'ms ease-out',

top: iBarTop + 'px'

})

clearTimeout(endTimeout);

endTimeout = setTimeout(function () {

setStyle(oScroll, {

transition: 'all 160ms ease-out'

})

setStyle(oBar, {

transition: 'all 160ms ease-out',

})

}, 500);

}

isMove = false;

document.documentElement.removeEventListener('touchmove', moveFn);

oContainer.removeEventListener('touchend', endFn);

}

document.documentElement.addEventListener('touchmove', moveFn);

oContainer.addEventListener('touchend', endFn);

})

function getStyle (obj, name) {

if(window.getComputedStyle) {

return getComputedStyle(obj, null)[name];

} else {

return obj.currentStyle[name];

}

}

function setStyle (obj, oStyle) {

for(var i in oStyle) {

obj.style[i] = oStyle[i];

}

}

function numberPx (num) {

return Number(num.split('px')[0]);

}

第二种代码

移动手指事件滚动使用速度

* {

margin: 0;

padding: 0;

}

.container {

position: relative;

margin: 50px;

width: calc(100% - 100px);

height: 400px;

border: 1px solid green;

box-sizing: border-box;

overflow: hidden;

}

.container .scroll {

position: absolute;

top: 0;

left: 0;

width: 100%;

}

.container p {

margin: 0 auto 10px;

width: 80%;

height: 80px;

border: 1px solid yellow;

}

.container .scroll:after {

content: '';

display: block;

clear: both;

}

.container .barBox {

position: absolute;

right: 2px;

top: 2px;

width: 3px;

height: calc(100% - 4px);

background: rgba(100, 200, 100, 0.3);

}

.container .barBox .bar {

position: absolute;

top: 0;

right: 0;

height: 0;

width: 100%;

background: #ccc;

}

var oContainer = document.getElementById('container');

var oScroll = oContainer.children[0];

var oBarBox = document.getElementById('barBox');

var oBar = oBarBox.children[0];

// 盒子尺寸

var iWrapperH = numberPx(getStyle(oContainer, 'height'));

var iScrollH = numberPx(getStyle(oScroll, 'height'));

var iBarBoxH = numberPx(getStyle(oBarBox, 'height'));

var iBarH = iWrapperH / iScrollH * iBarBoxH;

// 初始状态

setStyle(oBar, {

height: iBarH + 'px'

})

// 参数

var startTime = 0;

var endTime = 0;

var pastTime = 0; // 过去一次的时间

var nowTime = 0; // 当前移动的时间

var isMove = false;

var iBarTop = 0;

var timer = true;

oContainer.addEventListener('touchstart', function (e) {

startTime = new Date().getTime();

pastTime = startTime;

var startY = e.targetTouches[0].clientY;

var startTop = numberPx(getStyle(oScroll, 'top'));

var endY = startY;

var endTop = startTop;

timer = false;

var moveFn = function (e) {

isMove = true;

var nowY = e.targetTouches[0].clientY;

var nowTop = startTop;

endY = nowY;

var moveY = nowY - startY;

nowTop += moveY;

endTop = nowTop = getPos(nowTop);

setStyle(oScroll, {

top: nowTop + 'px'

})

setStyle(oBar, {

top: getBarTop(nowTop) + 'px'

})

}

var endFn = function (e) {

endTime = new Date().getTime();

var speed = (endY - startY) / (endTime - startTime);

if ( endTime - startTime <= 300 && isMove ) {

speed *= 16;

var f = 0,

top = endTop;

timer = true;

show();

function show () {

timer && requestAnimationFrame(show);

f = Math.min(Math.abs(speed) / 10, 0.5); //重点

if( speed > 0.2 ) {

speed -= f

} else if(speed < -0.2){

speed += f

} else {

timer = false

speed = 0

return

}

top += speed;

if ( top > 0 || top < iWrapperH -iScrollH ) {

timer = false

speed = 0

setStyle(oScroll, {

top: getPos(top) + 'px'

})

setStyle(oBar, {

top: getBarTop(getPos(top)) + 'px'

})

return

}

setStyle(oScroll, {

top: top + 'px'

})

setStyle(oBar, {

top: getBarTop(top) + 'px'

})

}

}

isMove = false;

document.documentElement.removeEventListener('touchmove', moveFn);

document.documentElement.removeEventListener('touchend', endFn);

}

document.documentElement.addEventListener('touchmove', moveFn);

document.documentElement.addEventListener('touchend', endFn);

})

function getPos (num) {

return num >= 0 ? 0 : (num <= iWrapperH - iScrollH ? iWrapperH - iScrollH : num);

}

function getBarTop (num) {

return -num / iScrollH * iBarBoxH;

}

function getStyle (obj, name) {

if(window.getComputedStyle) {

return getComputedStyle(obj, null)[name];

} else {

return obj.currentStyle[name];

}

}

function setStyle (obj, oStyle) {

for(var i in oStyle) {

obj.style[i] = oStyle[i];

}

}

function numberPx (num) {

return Number(num.split('px')[0]);

}

可以看看原生的效果

苹果移动效果

* {

margin: 0;

padding: 0;

}

.container {

position: relative;

margin: 50px;

width: calc(100% - 100px);

height: 400px;

border: 1px solid green;

box-sizing: border-box;

overflow: auto;

}

.container p {

margin: 0 auto 10px;

width: 80%;

height: 80px;

border: 1px solid yellow;

}

虽然现在看起来可以滚动了,但是感觉距离原生的惯性滚动、以及iScroll、better-scroll等的效果差的还是挺远的。看他们的源码,真是找不到哪儿是哪儿的东西,希望懂的大佬们,能够指点指点我!!!

手机html滚动原理,手机滚动-如何实现惯性滚动相关推荐

  1. html无缝滚动原理,Html5移动端获奖无缝滚动动画实现

    这篇文章主要介绍了Html5移动端获奖无缝滚动动画实现示例,内容挺不错的,现在分享给大家,也给大家做个参考. 本文介绍了Html5移动端获奖无缝滚动动画实现示例,分享给大家,具体如下: 需求分析 哈哈 ...

  2. js源生惯性滚动与回弹(备用)

    js源生惯性滚动与回弹(备用) js源生惯性滚动与回弹(备用) <!DOCTYPE html> <html lang="zh-CN"><head> ...

  3. 技术分享|手机推送原理剖析指南

    源宝导读:本文旨在对手机推送原理进行剖析和阐述,对业务开发做一些方向性的解惑. 一.手机推送的基本概念 --什么是手机推送? 百度词条:手机推送服务是指服务器 定向将信息实时送达手机的服务 词条中有2 ...

  4. android scroller,深入理解Android中Scroller的滚动原理

    View的平滑滚动效果 什么是实现View的平滑滚动效果呢,举个简单的例子,一个View从在我们指定的时间内从一个位置滚动到另外一个位置,我们利用Scroller类可以实现匀速滚动,可以先加速后减速, ...

  5. android 指南针 原理,手机指南针原理是什么?安卓/苹果手机指南针app工作原理介绍...

    手机指南针原理是什么?很多朋友想知道苹果/安卓手机指南针工作原理,为什么手机里的指南针APP能够分辨方位呢?如果你想知道答案的话,就请看下文吧. 指南针更专业的叫法是"电子罗盘", ...

  6. 手机双摄像头原理及产业解析----转载

    这个文章写得很好,特此转载,并致谢! 原文见于: https://blog.csdn.net/piaoxuezhong/article/details/79053974#comments 前记:本篇是 ...

  7. Camera--(7)手机双摄像头原理及产业解析

    本篇是对手机双摄原理及应用现状,未来布局的汇总. 为什么会出现双摄像头手机? 智能手机市场一直都是群雄争霸,竞争非常激烈.随着时代的发展,各大手机厂商的竞争焦点从以前的硬件军备竞赛逐渐延伸到影音娱乐领 ...

  8. 计算机 手机原理是什么,什么是手机投屏,手机投屏到电脑上的原理

    由于手机屏幕太小,感觉看电影.打游戏都不太舒服很多人并不满足于现状,所以想要将手机屏幕看看能不能投射到电脑或电视屏幕上,这样的话既能在大屏上体验游戏的快感又不会对自己的眼睛有所损伤真是一举两得的好处. ...

  9. android手机病毒原理,安卓手机病毒的原理是什么

    安卓手机病毒的原理是什么 Android系统因其开源性而受到了众多手机厂商和用户的倾爱,因为开源,所以降低了手机厂商的使用成本,也能让更多的开发者加入Android应用 的开发行列.下面是jy135小 ...

最新文章

  1. 修改MySQL字段为首字母大写
  2. win10 uwp 打包第三方字体到应用
  3. 来腾讯云开发者实验室 学习.NET
  4. java web 静态_「Java Web」主页静态化的实现
  5. leetcode面试题 17.15. 最长单词
  6. keil编译器如何生成二进制bin文件
  7. 看到抖音上 Python 工程师晒的工资条,我沉默了.....
  8. 通过OpenSSL创建自签名证书在Flask实现HTTPS
  9. Android精仿淘宝/QQ空间标题栏渐变效果
  10. RAID环境中增加容量-在线扩容
  11. H5第三方专业支付接口、安全稳定、费率优惠
  12. AUTOCAD——线宽设置
  13. 中国AI公司会议室取名简史
  14. TIBCO Rendezvous
  15. Python Factory 工厂方法
  16. REUSE_ALV_GRID_DISPLAY_LVC-可编辑单元格
  17. 在IDEA中集成Jenkins插件 解决Missing or bad crumb data异常
  18. 二元函数凹凸性判定及最值定理
  19. 运营商宽带网速为什么用bit而不用byte
  20. 队列BlockingQueue

热门文章

  1. c语言数组左下角便*,数据结构 - 数组
  2. 作者:张志恒(1990-),男,兰州大学资源环境学院硕士生。
  3. 作者:张悦今,女,中央财经大学信息学院讲师。
  4. 跳台阶游戏(洛谷P5613题题解,Java语言描述)
  5. Hdu-6243 2017CCPC-Final A.Dogs and Cages 数学
  6. rabbitmq中文教程python版 - Topics
  7. 7-7 六度空间(30 分)
  8. 13.4. 临时表是否需要建索引
  9. Effective objective-C 读书笔记 (第一部分)
  10. vue-cli配置jquery 以及jquery第三方插件