touchmove 事件指示的自定义滑动事件

Posted

技术标签:

【中文标题】touchmove 事件指示的自定义滑动事件【英文标题】:custom swipe event indicated by touchmove event 【发布时间】:2014-12-15 08:33:31 【问题描述】:

我正在尝试创建一种插件或事件,通过在 ipad 上滑动来 css 转换(移动)元素。为此,我目前正在使用 cocco 的出色工作小代码 sn-p:

(function(D)
  var M=Math,abs=M.abs,max=M.max,
  ce,m,th=20,t,sx,sy,ex,ey,cx,cy,dx,dy,l,
  f=
    touchstart:function(e)
    t=e.touches[0];
    sx=t.pageX;
    sy=t.pageY
  ,
  touchmove:function(e)
    m=1;
    t=e.touches[0];
    ex=t.pageX;
    ey=t.pageY
  ,
  touchend:function(e)
    ce=D.createEvent("CustomEvent");
    ce.initCustomEvent(m?(
    max(dx=abs(cx=ex-sx),dy=abs(cy=ey-sy))>th?
    dx>dy?cx<0?'swl':'swr':cy<0?'swu':'swd':'fc'
    ):'fc',true,true,e.target);
    e.target.dispatchEvent(ce);
    m=0
  ,
  touchcancel:function(e)
    m=0
  

for(l in f)D.addEventListener(l,f[l],false)
)(document);

对于过渡 rico st.cruz 的插件 jquery-transit.js 在我的网站上实现(当然还有 jquery)

// 用法(示例)

$("body").on( 'swu', function() 
    fullscreenSwipeUp = true;
    $("#Fullscreen").transition(  y: '-100%' , 900, 'easeInSine' )
 );

到目前为止一切顺利。 现在我的想法是通过一个额外的触摸移动事件来指示可能的“向上滑动”,该事件在手指点击时移动元素。我成功地添加了以下js:

// js 部分以更酷的方式集成

var startY;

window.addEventListener( 'touchstart', function(e) 
  e.preventDefault();   
  startY = e.targetTouches[0].pageY;
, false );

window.addEventListener( 'touchmove', function(e) 
  e.preventDefault();
  // check if transition is going on and animations are ready
  if ( !fullscreenSwipeUp )  // find better solution f.e. to dispatch event on fullscreen transition?

    var diffY = e.changedTouches[0].pageY - startY;

    // fullscreen transition
    if ( diffY <= 0 ) 
        $("#Fullscreen").css(  y: diffY  );
     else 
        // snap to clean starting value at bottom
        $("#Fullscreen").css(  y: 0  );
    ;
    // do something else to indicate that swipe will be concluded when finger leaves
    // min value based on variable th from custom swipe event
    if ( diffY < -20 ) 
        // indicate that swipe will be concluded
     else 
        // indicate that swipe will not conclude
    ;

  ;        
, false );

// fullscreen fall back to bottom if swipe not concluded
window.addEventListener( 'touchend', function(e) 
  e.preventDefault();   
  if ( !fullscreenSwipeUp ) 
    // fall back to starting values / dequeue for smoother transition on second time
    $("#Fullscreen").dequeue().transition(  y: 0 , 150, 'easeInSine' );      
  ;
, false ); 

现在我还看到,在此代码中,作为基本自定义事件和我的东西的双击移动事件,各个部分相互重叠。如果有人能给我一个如何整合这两个代码的想法,那就太棒了。或者也许存在这样的东西?我找不到合适的东西。

感谢您的帮助!

PS 我也尝试在这里创建一个小提琴:http://jsfiddle.net/Garavani/9zosg3bx/1/ 但遗憾的是,我太愚蠢了,无法让它与所有外部脚本一起工作:-(

jquery-transit.js: http://ricostacruz.com/jquery.transit/

编辑:

所以我按以下方式更改了我的代码。 我想我对原始的滑动事件(也包含触摸移动事件)和我想对元素做什么感到困惑。 尽管可能仍然一团糟,但它仍然有效。 我必须设置一种标志来检查是否执行了滑动以暂时禁用触摸移动事件。有没有更好的方法来做到这一点?感谢您的耐心等待!

var startY;
var swipeY = false; // for condition if condition for swipe is fullfilled
var swiped = false; // for check if swipe has been executed

window.addEventListener( 'touchstart', function(e) 
    e.preventDefault(); 
    startY = e.targetTouches[0].pageY;
, false );

window.addEventListener( 'touchmove', function(e) 
    e.preventDefault();
    // check if swipe already executed
    if ( !swiped )  // find better solution f.e. to dispatch event when swiped?

        var diffY = e.changedTouches[0].pageY - startY;

        // check for final swipe condition
        if ( diffY < -30 ) 
            swipeY = true;
            // do something with an element to indicate swipe will be executed
         else 
            swipeY = false;
            // do something with an element to indicate swipe will NOT be executed
        ;
    ;      
, false );

window.addEventListener( 'touchend', function(e) 
    e.preventDefault(); 
    if ( swipeY ) 
        swiped = true;
        // trigger the swipe action
     else 
        // let the element fall back to original state     
    ;
, false ); 

编辑 2:

var startY;
var swipeY = false;
var swiped = false;
var wh = $(window).height();

// fullscreen move on touchmove
function fm(e) 

    e.preventDefault();
    // check if transition is going on and animations are ready
    if ( !swiped && ready )  // !swiped is necessary, also / why?

        var diffY = e.changedTouches[0].pageY - startY;
        var scaleY = diffY/wh;
        // calculate transition intermediate values
        var osh = 0.91 - ( 0.09 * scaleY );
        var ofsc = 0.86 - ( 0.14 * scaleY );
        // fullscreen transition
        if ( diffY <= 0 ) 
            tfs(osh,[1,-scaleY],ofsc,diffY,0) // an extra module that does the animation with the calculated values
         else 
            // snap to clean starting values at bottom
            tfs(0.91,[1,0],0.86,0,0)
        ;
        // rotate arrow to indicate surpassing minimum touch move leading to swipe
        if ( diffY < -30 ) 
            swipeY = true;
            $arrowDown.addClass('rotation');
         else 
            swipeY = false;
            $arrowDown.removeClass('rotation');
        ;
    ;
;
// fullscreen swipe
function fs(e) 

    e.preventDefault();
    window.removeEventListener( 'touchmove', fm, false );
    if ( !swiped )  // this is necessary, also / why?          
        if ( swipeY )          
            $arrowbottomField.trigger('touchstart'); // trigger the full swipe (also available as element direct touch (on touch swiped is set to true in touchstart event handler, also)
            window.removeEventListener( 'touchend', fs, false );
         else 
            // fall back of animation to starting values
            tfs(0.91,[1,0],0.86,0,0);      
        ;
    ;
;

window.addEventListener( 'touchstart', function(e) 
    e.preventDefault(); 
    startY = e.targetTouches[0].pageY;  

    window.addEventListener( 'touchmove', fm, false );      
, false );

window.addEventListener( 'touchend', fs, false );

解释(尽我所能) 再次感谢可可的耐心。 与此同时,我再次修改了代码。 它有效 :-) 我知道这会让你眼花缭乱。

在我的网站上(应该也可以在 ipad 上工作,但不仅如此)有一个可以触摸的字段,并且全屏向上移动覆盖整个窗口(类似于 www.chanel.com ->“更多”) . 此外,(在 ipad 上)可以在整个身体上滑动来做同样的事情。

阶段:

第 1 阶段)用户点击和滑动(保持手指不动)全屏 div 跟随他的手指。

暂停 2) 如果滑动达到一定距离(手指仍然在上面),小箭头也会转动指示:如果您现在离开,将执行滑动

暂停 3) 手指仍然停留在距离变得小于完成滑动的距离时,箭头返回

第 4 阶段)用手指离开已经走过的距离决定全屏是完全向上移动还是回落(如果距离不够)

对于转动的小箭头,我可以使用你告诉我的类切换(比我做的更好!谢谢),但对于动画的其余部分,不是因为值很大程度上取决于窗口大小。我的整个网站的想法是浏览器窗口可以有任何大小或关系,所有内容都可以自行调整(随时包含水平和垂直居中)

对于手机来说,一切都完全改变了。

如果你想看一下:www.stefanseifert.com(如果你想看到效果(在 ipad 上),你必须通过触摸预告片 div 底部右上角的箭头来跳过介绍)

我知道还有很多其他的东西是最先进的编程技术(说得非常仔细:-),但在某种程度上它是有效的。 而且我雇不起几个星期的程序员来重做所有事情。 ;-) 这是一种边做边学(因为你可以猜到我以前从未编程过;-) 因此,我非常感谢您提供的每一点信息,并帮助我把小事做得更好。

如果有人会通过这里,我肯定会得到一些反对票 :-) 谢谢可可 圣诞快乐!

【问题讨论】:

最后一个代码有效吗?您还应该将刷卡设置回false..无论如何我看不出原始代码和您的..appart我只处理Y刷卡的任何区别...... 在使用原始滑动功能时,将 preventdefault 添加到您想要的元素。然后 swu 到那个...其中函数是一个简单的类切换,而 css 是 x,y jsfiddle.net/r2mhL785 我不确定你在制作动画时到底想做什么...... 如果您真的喜欢关注我的内容,请查看我的编辑 2。在您的代码的帮助下,我已经学到了一些东西,至少我希望如此。 【参考方案1】:

代码实际上是为低 cpu 设备、高性能.. 省去了 touchmove 内部的复杂计算。无论如何,要为您的元素设置动画(在 touchstart 和 touchend 之间),一个简单的解决方案是使用 css(不是 jquery 或其他资源密集型插件)。

然后从逻辑上思考...您无法确定在 touchstart 上滑动的方向...您可以在进行一些数学运算后在 touchend 事件中执行此操作。或者 touchmove 会破坏整个代码,如上所述。

选项 1(简单且高性能)

演示

http://jsfiddle.net/z7s8k9r4/

添加几行......

(function(D)
 var M=Math,abs=M.abs,max=M.max,
 ce,m,th=20,t,sx,sy,ex,ey,cx,cy,dx,dy,l,
 T,  //<- THE TARGET
 f=
  touchstart:function(e)
    t=e.touches[0];
    sx=t.pageX;
    sy=t.pageY;
    T=e.target; T.classList.add('sw'); //<- ADD A CUSTOM CLASS FOR SWIPES
  ,
  touchmove:function(e)
    m=1;
    t=e.touches[0];
    ex=t.pageX;
    ey=t.pageY
  ,
  touchend:function(e)
    ce=D.createEvent("CustomEvent");
    ce.initCustomEvent(m?(
    max(dx=abs(cx=ex-sx),dy=abs(cy=ey-sy))>th?
    dx>dy?cx<0?'swl':'swr':cy<0?'swu':'swd':'fc'
    ):'fc',true,true,e.target);
    e.target.dispatchEvent(ce);
    m=0;
    T.classList.remove('sw');  //<- REMOVE THE CLASS
  ,
  touchcancel:function(e)
    m=0
  
 
 for(l in f)D.addEventListener(l,f[l],false)
)(document);

现在定义 css 类

element.sw
 background-color:yellow;

在您的元素上为移动设备使用适当的 (HW) 动画

element
 background-color:green;
 -webkit-transition:background-color 200ms ease;

这是一个简单而肮脏的解决方案,它有效。保持简单。

该类仅适用于已定义的元素。 ;)

选项 2

忘记上面的代码...

这是另一种使用“反弹”制作“捕捉”动画的“高性能”方式。

代码稍微复杂一些...并使用鼠标..用触摸事件替换鼠标事件。

http://jsfiddle.net/xgkbjwxb/

还有更多的数据点

http://jsfiddle.net/xgkbjwxb/1/

注意:不要在移动设备中使用 jquery 或复杂的 js 插件。

额外

由于在没有触摸界面的电脑上工作确实有问题,所以我添加了一些行来强制鼠标根据我的功能要求模拟触摸。

http://jsfiddle.net/agmyjwb0/

编辑

这段代码应该做你想做的......

http://jsfiddle.net/xgkbjwxb/3/

【讨论】:

非常感谢,可可!你太棒了! 哇,查看您的代码和示例真是太有趣了!可悲的是,由于 ipad 上的弹性滚动,我在小提琴方面遇到了一些麻烦。然而,我的(糟糕的)代码的另一个想法是,动画不仅是具有固定起点和终点的简单 css 过渡,而且会整合实际的手指位置。因此我使用了过渡插件。您可以在 www.chanel.com 上看到类似的想法,他们使用的“更多”滚动效果。但我会尝试使用您的代码并查看。再次感谢! 所以我想我必须选择选项 2(好东西!)。我将设法用一些正弦轻松替换弹跳,并从鼠标切换到触摸。我需要的唯一一点建议是如何让身体敏感地移动 div 而不是 div 本身。总之很棒很棒的东西!再次感谢! 你好可可。再次感谢您的想法!我很想使用您的选项 2,但我什至没有成功更改代码,因为滑动由主体触发,而不是仅在元素本身上触发 :-( 如果您想看看我有什么,请参阅我的编辑完成了我愚蠢的代码。

以上是关于touchmove 事件指示的自定义滑动事件的主要内容,如果未能解决你的问题,请参考以下文章

移动端自定义事件

移动端表层div滑动,导致底层body滑动(touchmove的阻止)

vue监听滑动事件,隐藏移动端键盘或者input失去焦点

Touch事件详解及区别,触屏滑动距离计算

html5页面左右滑动是怎么实现的?

Touch事件及触屏滑动距离计算