JavaScript实现屏幕上下滑动的效果?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript实现屏幕上下滑动的效果?相关的知识,希望对你有一定的参考价值。

现在移动端有两种屏幕上下切换方案
第一种是用一个大的div(高度为所有页面合起来的高度)去包含所要切换的页面,然后利用大div的top值去切换
第二种是利用层级关系,只有两个上下级页面在切换
问题是那种方案更好?

参考技术A 可以考虑使用swiper插件 参考技术B 整屏切换吗? 参考技术C <!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="target-densitydpi=medium-dpi, width=device-width, height=device-height, initial-scale=1" />
<title></title>
<style type="text/css">
* margin:0; padding:0;
bodyborder:1px solid #066
.swap_h width:1000px; height:77px
.swap_h divwidth:108px; height:75px; word-wrap:break-word; word-break:break-all; float:left; border:1px solid #096; overflow:scroll
</style>
</head>
<body leftmargin="4" rightmargin="4" onswipe="g('dbg1').innerHTML='swipe b'" onswipeleft="g('dbg2').innerHTML='left b'" onswiperight="g('dbg2').innerHTML='right b'">
swipe swipeleft swiperight
<div id="div1" style="width:300px; overflow:hidden; height:77px; margin:0 auto">
<div style="word-break:break-all" class="swap_h" id="swap_1">
<div id="swap_11"> -1<?php echo date('H:i:s'); ?></div>
<div id="swap_12"> -2</div>
<div> -3</div>
<div> -4</div>
<div> -5</div>
<div> -6</div>
<div> -7</div>
<div> -8</div>
<div> -9</div>
<div> -0</div>
<div> -a</div>
<div> -b</div>
</div>
</div>
<div id="dbg">dbg</div>

<script language="javascript">
function l(s)
g('dbg').innerHTML = s;

function printEvent(evt)

try

var tmp = '';
for(var i in evt)

tmp += i+':'
var v = evt[i]+'';
if(v=='[object HTMLDivElement]')

tmp+=' <b>div</b> - '+evt[i].id+'<br/>';

else if(''+(evt[i])=='[object TouchList]')

tmp+=' <br/> <b>touchlist</b>:<div style="border:1px solid red; margin:1px"> ';
for(var x in evt[i])

if(''+(evt[i][x])=='[object Touch]')

tmp+='<br> ----'+x+':'+' <b>Touch</b><br/><div style="border:1px solid blue;margin:1px">';
for(var y in evt[i][x])

if(evt[i][x][y]=='[object HTMLDivElement]')

tmp+=' ----'+y+':<b>div</b> - '+evt[i][x][y].id+'<br/>';
else tmp+='<br> ----'+y+':'+evt[i][x][y]+'<br/>';

tmp+='</div>';
else
tmp+='<br> '+x+':'+evt[i][x]+'<br/>';

tmp+='</div>';
else if(typeof(evt[i])=='number')
tmp+='<font color="green">'+v+'</font><br/>';

else tmp+=''+v+'<br/>';

return tmp;
catch(e)
alert(e)


function getxy(e)
var a=new Array()
var t=e.offsetTop;
var l=e.offsetLeft;
var w=e.offsetWidth;
var h=e.offsetHeight;
while(e=e.offsetParent)
t+=e.offsetTop;
l+=e.offsetLeft;

a[0]=w;a[1]=h;
a[2]=l;a[3]=t;
return a;

function touch(obj,func)

try
if(arguments.length>2)
this.leftRightOnly = arguments[2];
else
this.leftRightOnly = false;

if(arguments.length>4)//4,5个参数设置后会帮你设定子元素的宽度,帮助滚动效果
var fchild = g(arguments[3]);
if(fchild)
var fchildCTagName = arguments[4];
var childs = fchild.getElementsByTagName(fchildCTagName);
var w = 0;

for(var i=0;i<childs.length;i++)
var xy = getxy(childs[i]);
w += xy[0];

fchild.style.width = w+"px";



this.swipe_function[obj.id] = func;
this.id = obj.id;
if(!this.id)
alert("第一个参数必须有一个id");
return;

this.isPc = navigator.userAgent.indexOf('Windows')!=-1||navigator.platform.indexOf('Mac')!=-1;
this.startFlag = false;
obj.data = this;

if(this.isPc)
this.bind(obj,'mousedown',function(e)this.data.touchstart(e););
this.bind(obj,'mouseup',function(e)this.data.touchend(e););
this.bind(obj,'mouseout',function(e)this.data.touchend(e););
this.bind(obj,'mousemove',function(e)this.data.touchmove(e););
else
this.bind(obj,'touchstart',function(e)this.data.touchstart(e););
this.bind(obj,'touchend',function(e)this.data.touchend(e););
this.bind(obj,'touchmove',function(e)this.data.touchmove(e););

catch(e)
alert("touch: "+e);


touch.prototype.tch_start = ;
touch.prototype.tch_mv = ;
touch.prototype.swipe_function = ;
touch.prototype.bind = function(obj,evt,fun)

if(typeof obj.attachEvent != 'undefined')

obj.attachEvent('on'+evt,fun);
else
obj.addEventListener(evt,fun,true);


touch.prototype.touchstart=function(evt)

try
if(this.isPc)
var tch = evt;
else
var tch = evt['touches'][0];

if(this.isPc)
var id = this.id;
else
var id = tch.target.id
this.tch_start[id] = [tch.clientX,tch.clientY,tch.clientX];
l("this.tch_start[id]="+this.tch_start[id]+",id="+id)
this.startFlag = true;
evt.preventDefault();
catch(e)
alert('this.tch_start='+this.tch_start+'<br />'+e);


touch.prototype.touchend=function (evt)

try
if(!this.startFlag) return;
if(!this.isPc && (typeof(evt.changedTouches)=='undefined'||evt.changedTouches.length<1)) return;

if(this.isPc)
var id = this.id;
else
var id = evt.changedTouches[0].target.id;

var pid = evt.currentTarget.id;
var now = this.tch_mv[id];
var start = this.tch_start[id];

l('end= '+start+","+now+",id="+id)

var xdiff = now[0]-start[0];
var ydiff = now[1]-start[1];

var f = this.swipe_function[pid];
evt.preventDefault();
this.startFlag = false;
if(Math.abs(xdiff)>Math.abs(ydiff))

if(xdiff<0)

this.swipe(pid,'left',xdiff,f);
return;

if(xdiff>0)

this.swipe(pid,'right',xdiff,f);
return;

else
if(ydiff<0)

this.swipe(pid,'up',ydiff,f);
return;

if(ydiff>0)

this.swipe(pid,'down',ydiff,f);
return;


catch(e)
alert('touchend error='+e)


touch.prototype.touchmove=function(evt)

try
if(!this.startFlag) return;
if(this.isPc)
var id = this.id;
var tch = evt;
else
var tch = evt['touches'][0];
var id = tch.target.id;

var now = [tch.clientX,tch.clientY];
this.tch_mv[id] = now;

if(this.leftRightOnly)

var start = this.tch_start[id];
l('move='+start+","+now+",id="+id)
var xdiff = start[2] - now[0];
var obj = g(this.id);
obj.scrollLeft += xdiff;
start[2] = now[0];

evt.preventDefault();
catch(e)
console.log('touchmove error='+e);
//l(printEvent(evt));


touch.prototype.swipe = function(pid,dir,xydiff,func)

if(typeof(swiping)=='undefined') swiping = false;
if(swiping) return;
swiping = true;
try
var obj = g(pid);
var moveDis = obj.style.width?parseInt(obj.style.width,10):300;
if(this.leftRightOnly)

var cur_scrollleft = obj.scrollLeft;
var moved = cur_scrollleft%moveDis;
if(dir=='right')
moveDis = moved;
else if(dir=='left')
moveDis -= moved;
else
if(moved>moveDis/2)

var factor = 1;
moveDis = moveDis - moved;
else
var factor = -1;
moveDis = moved;


//g('dbg').innerHTML = 'dir='+dir+',cur_scrollleft='+cur_scrollleft+',moveDis='+moveDis+'<br/>'+g('dbg').innerHTML;

if(dir=='left')
func(pid,moveDis,1);
else if(dir=='right')
func(pid,moveDis,-1);
else
swiping = false;
xydiff = Math.abs(xydiff)*2;
if(dir=='up')
var scrollMoveValue = xydiff;
else
var scrollMoveValue = xydiff*-1;

document.body.scrollTop = document.body.scrollTop+scrollMoveValue;
if(this.leftRightOnly)

func(pid,moveDis,factor);


catch(e)
alert(e)



function g(id)

return document.getElementById(id);

var swiping = false;
var step = 16;
function slowmv(pid,v,v1)

try
var moved = arguments.length==4?arguments[3]:0;
if(moved+step>v)
var _step = v-moved;
else
var _step = step;

moved+=_step;
var obj = g(pid);
var display_width = obj.style.width?parseInt(obj.style.width,10):0;

var new_left = obj.scrollLeft+_step*v1;
if((v1>0&&new_left+display_width>=obj.scrollWidth)||(v1<0&&new_left<=0)) new_left = new_left<=0?0:(obj.scrollWidth-display_width);
obj.scrollLeft = new_left;

if(moved<v)

if(new_left>=obj.scrollWidth-display_width||new_left<=0)
swiping = false;
return;

setTimeout(function()slowmv(pid,v,v1,moved);,25);
else swiping = false;
catch(e)
alert('slowmv error='+e+',pid='+pid+',v='+v+',v1='+v1);


//div1是最外的框,决定了可以看到的范围;swap_1是里面很宽的内容,每次滑动显示一部分它的内容;最后一个参数是swap_1里面子元素的标签名,如果swap_1里面是图片,就传img
var t = new touch(g('div1'),slowmv,true,'swap_1', 'div');

</script>
</body>
</html>

基于vue实现上下滑动翻页效果

    18年年底的时候,一直在做年度报告的H5页面,因为项目需要,需要实现上下滑动翻页,并且上滑的页面比正常页面的比例要缩小一定比例。

    效果类似于http://www.17sucai.com/pins/demo-show?id=7834,这个链接是基于jquery实现的,我写的是和这个例子效果一样,只不过是用vue实现的。

    代码地址:https://github.com/dreamITGirl/vuepageturn  //demo

    首先介绍一下,这个项目依赖的插件:上下滑动翻页使用了v-touch,是基于hammer.js进行的vue封装。也可以不用这个插件写,直接用js原生,通过touchStart,touchMove,touchEnd来实现也是可以的;

 

    现在总结一下几点,是我在写代码的时候遇到的坑。

             1、因为我是使用的是v-touch里的pan属性及它附带的方法和事件。所以,在组件内部如果还有滚动的区域,就可能会出现冲突,最后项目上线之前,仍没有彻底解决。

                 不管是用v-touch还是用js原生,都会出现这个问题,在实现上下页面滑动切换时,采用了纯css去控制上下滑动的距离。所以,css可能会冲突。所以,建议不要在使用v-touch或者js原生滚动区域内部再次出现滚动区域。

下一篇博客会重点说一下这个问题的解决方式。

  <v-touch class="container" 
                 @panstart.prevent="panStart"
                 @panmove.prevent="panMove"
                 @panend.prevent="panEnd">
            <component v-for="(val,index) in componentList" 
                        :key="index" :is="val" 
                        :style="{
                            zIndex:zIndex(index),
                            top:top(index),
                            transition:`all ${transition(index)}s`,
                            transform:`translateY(${top(index)}) scale3d(${scale(index)},1,${scale(index)})`
                        }"
                        
            ></component>  
              
   </v-touch>

  如果在component中仍有滑动的区域的话,就会产生css冲突。

     2、滚动距离的计算

      看图理解

      技术分享图片 

         页面1,页面2,页面3分别对应我要上下滑动切换的页面,并且,1,2,3分别对应组件中的三个组件,也就是说,每个页面都是一个独立的组件。而这些组件是通过v-for的方式循环渲染的。

         需要控制的是每个页面的top值,z-index值,scale值,以及为了实现平滑的效果transition的过渡时间。

           当页面向上(下)滑动时,页面3(页面1)就变成了当前展示的页面,页面2就变成了前一个页面(下一个页面),因为页面3(页面1)是最后(第)一个页面了,用户不能再继续向下滑,

         所以,我们需要在panmove和panend时去依据当前的index值和当前展示的组件数组中最后一项和第一项去判断

         重点说一下在panmove的时候,也就是在滚动过程中的时候,页面的变化以及top值和滑动的距离是如何计算的。还是看图:

         技术分享图片

      这个里面最难理解的就是这个上滑,或者下滑的距离,在我的代码里,1.0版本的并没有解决两个页面始终差一段距离,这个距离就是distance的2/3,在panend的时候,我们需要看一下用户滑动的距离是不是可以翻页,如果距离很小,则不能翻页,最好加一下判断。

      上滑之后,页面1就变成了其他页面,页面2变成了前一个页面,页面3变成了当前页面,对这3个页面来说,它们各向上走了一个屏幕的高度,而页面3的高度top值变成了0,页面2变成了-1*屏幕的高度。页面1则变成了-2 * 屏幕的高度,但是对于页面1来说,已经变成了其他的图片,所以它的高度,是(它的index-当前的index)*屏幕的高度。

      对于当前上滑(下滑)的页面缩放的解决,是在panstart的时候,设置当前页面的缩放率为1,在panmove的时候根据滑动的距离,随机设置缩放率。在panend的时候,设置延迟,使缩放率变成。

      所以,正常的滑动过程中的样式是

      技术分享图片

      具体的代码,大家可以去github上自行下载使用,如果不使用v-touch,也可以用touchStart,touchMove,touchEnd分别对应显示。

 

  

 

         

        

    

    

以上是关于JavaScript实现屏幕上下滑动的效果?的主要内容,如果未能解决你的问题,请参考以下文章

JS实现安卓手机端触摸屏幕左右滑动显示的效果

请问有人用videojs实现上下滑动切换视频功能

微信小程序实现上下左右滑动触发联动选项卡绝对值事件parsestringifyMathatanabsfindIndex

【Axure】触摸屏上下滑动效果

android开发中,怎么实现上下滑动,不是ScrollView,我要的是一次滑动整个页面,跟横向滑动效果一样。。

Android实现布局顶部底部上下滑动效果