手机html滚动原理,手机滚动-如何实现惯性滚动
手機慣性滾動時應該怎么計算速度,以及之后速度怎么遞減等問題
因為要做一個手機端的滾動插件,所以想模擬出手機原生的慣性滾動,就是手指快速滑動后,手機頁面在手指抬起來之后,依然會滾動一段距離的效果。
現在我嘗試了兩種方法
1、在手指start與end之間時間少于300ms時,根據手指移動距離得出需要繼續(xù)滾動的長度,在end之后通過transition與top實現動畫效果
2、在手指end之后通過手指的移動距離與使用時間計算平局速度,如果使用時間少于300ms,則通過requestAnimationFrame循環(huán)調用一個每次都遞減速度的函數,當速度很小時跳出函數循環(huán)。在函數中每一次都設置一次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;
// 初始狀態(tài)
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;
// 初始狀態(tài)
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滚动原理,手机滚动-如何实现惯性滚动的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++学习笔记之——引用 内联函数
- 下一篇: 使用Opencv的一些注意事项