移动端开发实例 | 圖片滑動 | 模擬滾動條
圖片滑動
onmousedown -->> ontouchstart按下瞬间 ;
onmousemove -->> ontouchmove移动过程 ;
onmouseup -->> ontouchend手指抬起 ,只针对单手操作 ;
對象操作:
var touchs = e.changedTouches[0]
//先获取对象属性,手指操作的集合; 几个手指即有几项,所以单指是[0] ;
所以與元素拖動類似,結構是:
_ul.ontouchstart = function(e){
_ul.ontouchmove = function(e){
...
}
_ul.ontouchend = function(e){
...
this.ontouchmove = this.ontouchend = null;
}
}
第一張圖與最後一張圖時速度變慢,所以使用移動距離為1/3
this.style.left = (touchs.pageX - downX) / 3 + 'px'
若第一張與第二張中間切換時,速度不同會出現跳動,所以需要再move過界時重新獲取downX,並且設置開頭只獲取一次;
b = false
downX = touchs.pageX
如果快速移動時,可快速滑動,需要設置時間,start時的時間,到end的時間
downTime = Date.now();
_ul.ontouchend = function(e){
...
Date.now() - downTime < 300
}
<div id="div">
<ul id="ul1">
<li><img src="iosimg/1.jpg" alt=""/></li>
<li><img src="iosimg/2.jpg" alt=""/></li>
<li><img src="iosimg/3.jpg" alt=""/></li>
<li><img src="iosimg/4.jpg" alt=""/></li>
<li><img src="iosimg/5.jpg" alt=""/></li>
</ul>
</div>
var _div = document.getElementById('div')
var _ul = document.getElementById('ul1')
var _li = _ul.getElementsByTagName('li')
var w = _li[0].offsetWidth;
_ul.style.width = w * _li.length + 'px'
document.ontouchmove = function (e) { //阻止默認滑動
e.preventDefault()
}
var downX = 0; //手指點下的坐標
var downLeft = 0;
var downTime = 0;
var inow = 0;
_ul.ontouchstart = function (e) {
var touchs = e.changedTouches[0] //先获取对象属性,手指操作的集合; 几个手指即有几项,所以单指是[0]
downX = touchs.pageX
downLeft = this.offsetLeft;
var b = true;
downTime = Date.now();
_ul.ontouchmove = function (e) {
var touchs = e.changedTouches[0]
if (this.offsetLeft >= 0) {
if (b) { //第二张一点开始滑到,到第一张时,如果不重新获取downX值,第二张速度仅为1/3,所以会突然跳动,设开头的意思是在move移动中,只需获取一次,不然只要move则每一秒都会重新获取;
b = false
downX = touchs.pageX
}
this.style.left = (touchs.pageX - downX) / 3 + 'px'
}
else if (this.offsetLeft < _div.offsetWidth - _ul.offsetWidth) {
if (b) { //第二张一点开始滑到,到第一张时,如果不重新获取downX值,第二张速度仅为1/3,所以会突然跳动,设开头的意思是在move移动中,只需获取一次,不然只要move则每一秒都会重新获取;
b = false
downX = touchs.pageX
}
this.style.left = (touchs.pageX - downX) / 3 + (_div.offsetWidth - _ul.offsetWidth) + 'px'
}
else {
this.style.left = touchs.pageX - downX + downLeft + 'px'
}
}
_ul.ontouchend = function (e) {
var touchs = e.changedTouches[0]
if (touchs.pageX < downX) { //向左
if (inow != _li.length - 1) {
if (downX - touchs.pageX > w / 2 || Date.now() - downTime < 300 && downX - touchs.pageX > 30) { //必须过一半才滑动
inow++ //确定方向,快速滑动,防止点击
}
}
tMove(this, {left: -w * inow}, 500, 'easeOut')
}
else { //向右
if (inow != 0) {
if (touchs.pageX - downX > w / 2 || Date.now() - downTime < 300 && touchs.pageX - downX > 30) {
inow--
}
}
tMove(this, {left: -w * inow}, 500, 'easeOut')
}
this.ontouchmove = this.ontouchend = null;
}
}
*{ margin: 0; padding: 0;}
#div{ width: 470px; height: 150px; margin: 50px; position: relative;overflow: hidden; }
#ul1{ position: absolute; left: 0; } /*这种而已没有宽度则li不会有float效果;*/
#ul1 li{ width: 470px; height: 150px; float: left;list-style:none;}
模擬滾動條:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title><meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"/>
<meta name="format-detection" content="telephone=no"/>
<meta name="format-detection" content="email=no"/>
</head>
<body>
<style>
*{ margin: 0; padding: 0;}
#div1{ width: 200px; height: 200px;border:1px solid #000; position: relative; margin:100px;}
#ul1{ position: absolute; top: 0;width: 100%;}
#bar{ width: 2px; height: 100px; position: absolute; top: 0;right: 2px; background: #999; border-radius: 20px; display: none;}/* divH/ulH = barH/divH borH = divH*divH/ulH */
</style>
<div id="div1">
<ul id="ul1">
</ul>
<div id="bar"></div>
</div>
</body>
<script>
document.ontouchmove = function (e) {
e.preventDefault()
}
var _div = document.getElementById('div1')
var _ul = document.getElementById('ul1')
var _bar = document.getElementById('bar')
for(var i=0;i<101;i++){
var _li = document.createElement('li')
_li.innerHTML = i;
_ul.appendChild(_li)
}
var downY = 0;
var downTop = 0;
var prevY = 0;
var _t = null;
var barH = _div.offsetHeight*_div.offsetHeight/_ul.offsetHeight
if(barH<=40){
barH = 40;
}
else if(_ul.offsetHeight<_div.offsetHeight){
barH = 0;
}
_bar.style.height =barH + 'px'
_ul.ontouchstart = function (e) {
var touchs = e.changedTouches[0]
downY = touchs.pageY
downTop = this.offsetTop;
prevY = touchs.pageY;
var _speedY = 0;
var b = true;
_ul.ontouchmove= function (e) {
_bar.style.opacity = 1;
_bar.style.display = 'block';
var touchs = e.changedTouches[0]
_speedY = touchs.pageY - prevY; //出手速度 move时的点 - 前一个点,
prevY = touchs.pageY; //注意永运是最后一个点 - 前一个点,所以给值后要把prevY还原回前一个点;注意理解;
if(this.offsetTop>=0){ //头部
if(b){
b = false;
downY = touchs.pageY
}
this.style.top = (touchs.pageY - downY)/3 + downTop + 'px'
_bar.style.height = barH * (1- this.offsetTop/_div.offsetHeight) +'px'//原高度 * 比例
_bar.style.top = 0
}
else if(this.offsetTop<=_div.offsetHeight - _ul.offsetHeight){
if(b){
b = false;
downY = touchs.pageY
}
this.style.top = (touchs.pageY - downY)/3 + _div.offsetHeight - _ul.offsetHeight + 'px'
_bar.style.height = barH * (1- Math.abs((this.offsetTop-(_div.offsetHeight - _ul.offsetHeight))/_div.offsetHeight)) +'px'//原高度 * 比例 //尾部找一个0-1越来越小的值
_bar.style.top = _div.offsetHeight - _bar.offsetHeight + 'px'
}
else{this.style.top = touchs.pageY - downY + downTop + 'px';
//在move时找bar的滚动位置比例
var scaleY = this.offsetTop/(_div.offsetHeight - _ul.offsetHeight) //最小值即move时不断变化的this.offsetTop,最大值为div.offsetHeight - _ul.offsetHeight; 0-1的比值
_bar.style.top = scaleY * (_div.offsetHeight - _bar.offsetHeight)+'px'
}
}
_ul.ontouchend = function () {
this.ontouchmove = this.ontouchend = null;
//1/手指起时开始做运动
//_speedY
var _this = this
clearInterval(_t)
_t = setInterval(function () {
if(Math.abs(_speedY)<=1 || _this.offsetTop>50 || _this.offsetTop<=_div.offsetHeight - _ul.offsetHeight - 50){ //停
clearInterval(_t)
if(_this.offsetTop>=0){ //限制头
tMove(_this,{top:0},400, function () {
tMove(_bar,{opacity:0},400, function () {
this.style.display = 'none'
})
})
tMove(_bar,{height:barH},400)
}
else if(_this.offsetTop <= _div.offsetHeight - _ul.offsetHeight ){ //限制尾
tMove(_this,{top:_div.offsetHeight - _ul.offsetHeight },400, function () {
tMove(_bar,{opacity:0},400, function () {
this.style.display = 'none'
})
})
tMove(_bar,{height:barH,top:_div.offsetHeight - barH},400, function () {
tMove(_bar,{opacity:0},400)
_bar.style.display = 'none'
})
}
else{ tMove(_bar,{opacity:0},400, function () {
this.style.display = 'none'
})
}
}
else{ //走
_speedY *=0.95;
_this.style.top = _this.offsetTop+ _speedY + 'px'
//bar头尾加运动
if(_this.offsetTop>=0){
_bar.style.height = barH * (1- _this.offsetTop/_div.offsetHeight) +'px'//原高度 * 比例
_bar.style.top = 0
}
else if(_this.offsetTop<=_div.offsetHeight - _ul.offsetHeight){
_bar.style.height = barH * (1- Math.abs((_this.offsetTop-(_div.offsetHeight - _ul.offsetHeight))/_div.offsetHeight)) +'px'//原高度 * 比例 //尾部找一个0-1越来越小的值
_bar.style.top = _div.offsetHeight - _bar.offsetHeight + 'px'
}
else{}
//在move时找bar的滚动位置比例
var scaleY = _this.offsetTop/(_div.offsetHeight - _ul.offsetHeight) //最小值即move时不断变化的this.offsetTop,最大值为div.offsetHeight - _ul.offsetHeight; 0-1的比值
_bar.style.top = scaleY * (_div.offsetHeight - _bar.offsetHeight)+'px'
tMove(_bar,{top:scaleY * (_div.offsetHeight - _bar.offsetHeight)},400)
}
},30)
}
}
function tMove(obj, json, times, fx, fn) {
if (typeof times == 'undefined') {
times = 400;
fx = 'linear';
}
if (typeof times == 'string') {
if (typeof fx == 'function') {
fn = fx;
}
fx = times;
times = 400;
}
else if (typeof times == 'function') {
fn = times;
times = 400;
fx = 'linear';
}
else if (typeof times == 'number') {
if (typeof fx == 'function') {
fn = fx;
fx = 'linear';
}
else if (typeof fx == 'undefined') {
fx = 'linear';
}
}
var iCur = {
}; //不變,不能寫在定時器裏 b
for (var attr in json) {
iCur[attr] = 0;
if (attr == 'opacity') {
iCur[attr] = Math.round(css(obj, attr) * 100);
}
else {
iCur[attr] = parseInt(css(obj, attr));
}
}
var startTime = now();
clearInterval(obj._t);
obj._t = setInterval(function () {
var changeTime = now();
var t = times - Math.max(0, startTime - changeTime + times);
//在time的範圍內越來越小 2000-0;
for (var attr in json) {
var value = Tween[fx](t, iCur[attr], json[attr] - iCur[attr], times); //目的,通過js獲取tbcd值
if (attr == 'opacity') {
obj.style.opacity = value / 100;
obj.style.filter = 'alpha(opacity=' + value + ')';
}
else {
obj.style[attr] = value + 'px';
}
}
if (t == times) {
clearInterval(obj._t);
fn && fn.call(obj);
}
}, 13)
}
function now() {
return (new Date()).getTime();
}
var Tween = {
linear: function (t, b, c, d) { //匀速
return c * t / d + b;
},
easeIn: function (t, b, c, d) { //加速曲线
return c * (t /= d) * t + b;
},
easeOut: function (t, b, c, d) { //减速曲线
return - c * (t /= d) * (t - 2) + b;
},
easeBoth: function (t, b, c, d) { //加速减速曲线 缓冲
if ((t /= d / 2) < 1) {
return c / 2 * t * t + b;
}
return - c / 2 * ((--t) * (t - 2) - 1) + b;
},
easeInStrong: function (t, b, c, d) { //加加速曲线
return c * (t /= d) * t * t * t + b;
},
easeOutStrong: function (t, b, c, d) { //减减速曲线
return - c * ((t = t / d - 1) * t * t * t - 1) + b;
},
easeBothStrong: function (t, b, c, d) { //加加速减减速曲线
if ((t /= d / 2) < 1) {
return c / 2 * t * t * t * t + b;
}
return - c / 2 * ((t -= 2) * t * t * t - 2) + b;
},
elasticIn: function (t, b, c, d, a, p) { //正弦衰减曲线(弹动渐入)
if (t === 0) {
return b;
}
if ((t /= d) == 1) {
return b + c;
}
if (!p) {
p = d * 0.3;
}
if (!a || a < Math.abs(c)) {
a = c;
var s = p / 4;
} else {
var s = p / (2 * Math.PI) * Math.asin(c / a);
}
return - (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
},
elasticOut: function (t, b, c, d, a, p) { //正弦增强曲线(弹动渐出)
if (t === 0) {
return b;
}
if ((t /= d) == 1) {
return b + c;
}
if (!p) {
p = d * 0.3;
}
if (!a || a < Math.abs(c)) {
a = c;
var s = p / 4;
} else {
var s = p / (2 * Math.PI) * Math.asin(c / a);
}
return a * Math.pow(2, - 10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
},
elasticBoth: function (t, b, c, d, a, p) {
if (t === 0) {
return b;
}
if ((t /= d / 2) == 2) {
return b + c;
}
if (!p) {
p = d * (0.3 * 1.5);
}
if (!a || a < Math.abs(c)) {
a = c;
var s = p / 4;
}
else {
var s = p / (2 * Math.PI) * Math.asin(c / a);
}
if (t < 1) {
return - 0.5 * (a * Math.pow(2, 10 * (t -= 1)) *
Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
}
return a * Math.pow(2, - 10 * (t -= 1)) *
Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b;
},
backIn: function (t, b, c, d, s) { //回退加速(回退渐入)
if (typeof s == 'undefined') {
s = 1.70158;
}
return c * (t /= d) * t * ((s + 1) * t - s) + b;
},
backOut: function (t, b, c, d, s) {
if (typeof s == 'undefined') {
s = 3.70158; //回缩的距离
}
return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
},
backBoth: function (t, b, c, d, s) {
if (typeof s == 'undefined') {
s = 1.70158;
}
if ((t /= d / 2) < 1) {
return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
}
return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
},
bounceIn: function (t, b, c, d) { //弹球减振(弹球渐出)
return c - Tween['bounceOut'](d - t, 0, c, d) + b;
},
bounceOut: function (t, b, c, d) {
if ((t /= d) < (1 / 2.75)) {
return c * (7.5625 * t * t) + b;
} else if (t < (2 / 2.75)) {
return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;
} else if (t < (2.5 / 2.75)) {
return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;
}
return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;
},
bounceBoth: function (t, b, c, d) {
if (t < d / 2) {
return Tween['bounceIn'](t * 2, 0, c, d) * 0.5 + b;
}
return Tween['bounceOut'](t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;
}
}
function css(obj, attr) {
return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj) [attr]
}
</script>
</html>