【问题标题】:How can I stop mobile Safari from pausing before beginning a transition如何在开始转换之前阻止移动 Safari 暂停
【发布时间】:2012-02-24 15:49:12
【问题描述】:

这很奇怪!

概述:
我正在创建一个网络应用程序,并创建了一个类似于您在 Facebook 应用程序中找到的菜单。向右滑动它会显示,向左滑动它会隐藏。

我通过将 touchstart 事件绑定到页面主体来做到这一点,此时我记录了手指按下的起点并还绑定了一个 touchmovetouchend 事件。触摸移动事件找到当前手指位置并通过设置 translate3d(x,y,z) 来移动包含页面内容的 div 以匹配手指位置。

它实际上真的很棒。

touchend 之后,我会计算手指移动的距离是否足以触发要显示的菜单或内容是否返回到其原始位置。无论选择如何,我都会应用一个类,该类又将 -webkit-transition: -webkit-transform 等 应用于内容 div。然后我设置了确定的结束位置,再次使用 translate3d(x,y,z) 并设置了一个变量来阻止任何进一步的点击暂时工作。

这就是问题所在!

问题:
此时,如果内容很简单,具有基本结构,即文章布局页面,那么过渡是快速而即时的。然而!如果内容很复杂,即一个大数据表,那么会有一个暂停,从 1 到 30 秒……非常令人沮丧。

当它最终起作用时,回调会解除与 body 的 touchmove 和 touchend 事件的绑定,并且取消设置停止点击的变量,我们已准备好重新开始。

我在 iPad 1 上进行测试。滑动速度与暂停时间之间似乎没有任何关联。内容移动的距离之间也没有任何距离。

最后,我认为这是关键!
有一个按钮可以自动执行相同的打开关闭操作(再次,如 facebook),它工作正常,如果你滑动它,它会暂停,然后你点击该按钮它会立即开始工作,尽管它在切换时方向错误在已设置为打开的变量上。这几乎就像它清除了某种动画队列并自行整理...

一些代码:
javascript

$body.bind({
    'touchstart': function(e){

        if( !swipeBan ){

            // Reset
            var used = false,
                triggered = false,
                dir = false;

            // Get start point
            start.x = e.originalEvent.touches[0].pageX;
            start.y = e.originalEvent.touches[0].pageY;

            $body.bind({
                'touchmove':    function(e){

                    // Get current value (will be the end value too)
                    end.x = e.originalEvent.touches[0].pageX;
                    end.y = e.originalEvent.touches[0].pageY;

                    // If we have not chosen a direction, choose one
                    if( !dir ){

                        dir = getDir();

                    }else{

                        var left = open && dir == 'left',
                            right = !open && dir == 'right';

                        if( left || right ){

                            var x = left ? maxSwipe - getDist('left') : getDist('right');

                            $content.setTransform(x);

                            used = true;
                            triggered = left ? maxSwipe - x > swipeTrigger : x > swipeTrigger;

                            e.preventDefault();

                        }

                    }

                },
                'touchend': function(e){

                    // Only go further if we are going the correct direction
                    if( used ){

                        swipeBan = true;

                        // Get ready for animation
                        function done(){

                            // Get touching!
                            swipeBan = false;

                            // Stop animating
                            $content.removeClass('animate');

                        }

                        // Add animate class
                        $content.addClass('animate');

                        // Set the value
                        if( ( !open && triggered ) || ( open && !triggered ) ){

                            $content.setTransform(maxSwipe,0,function(){
                                done();
                            });

                            $body.removeClass('closed');

                            open = true;

                        }else if( ( !open && !triggered ) || ( open && triggered ) ){

                            $content.setTransform(0,0,function(){
                                done();
                            });

                            $body.addClass('closed');

                            open = false;

                        }

                    }

                    // Unbind everything
                    $body.unbind('touchmove touchend');

                }
            });

        }else{

            e.preventDefault();

        }

    }
});

您将在上面看到使用的设置转换插件。

$.fn.setTransform = function(x,y,callback){

    y = y ? y : '0';

    var $this = $(this);

    if( callback ){

        $this.one('webkitTransitionEnd',function(){

             callback.apply(this);

        });

    }

    $this.css({
        '-webkit-transform':    'translate3d(' + x + 'px,' + y + '%,0)'
    });

    return this;

}

CSS,很简单。还应用了其他样式,但它们纯粹是视觉上的东西:

#content.animate {
    -webkit-transition: -webkit-transform .3s cubic-bezier(.16,0,0,1);
}

抱歉,这篇文章太长了,这一直困扰着我!如果我无法解决问题,我将不得不把它撕掉。

我希望有人以前见过这个,并且可以提供帮助。 (或者可以在上面的代码中看到一个非常明显的错误!)

谢谢,

会 :)

【问题讨论】:

  • 我正在为类似的问题而苦苦挣扎,尽管我的用例要复杂得多,在这里我没有足够的空间来解释它。我也没有答案。但是,我在 Instruments 下运行我的应用程序以查看发生了什么,在我看来,WebKit 陷入了一个循环,试图计算页面的一部分的样式。我的理论是样式计算错过了某种截止日期,并且过渡永远不会向前增加。似乎没有过渡有效,但触发完整的样式重新计算可以修复它。我建议您简化 CSS,看看是否有帮助。
  • 是的,我一直在删除样式以修复它。正如您所料,任何不透明或模糊的东西都会加快速度,主要是阴影。遗憾的是,无论移动的内容如何,​​实际的滑动都很好而且很快。不过还是谢谢克里斯。

标签: jquery css ios transitions translate3d


【解决方案1】:

我最终解决了这个问题,认为它可能对其他人有用!

不要在页面中添加任何类,在 touchmove 过渡结束和完成移动的过渡开始之间。

我的流程曾经是:

  1. 在 touchstart 上获取手指 x
  2. 在基于当前位置和开始的 touchmove 位置元素上 位置
  3. 在触摸结束时,决定是继续还是反转动画 基于移动的距离。
  4. 向父元素添加一个关闭或打开的类,确定 最终位置。

但是,添加这个类会强制 safari 应用任何显然非常密集的样式更改,即使更改很少或什至没有更改。这就是暂停的原因。

我更改了我的流程以使用 javascript 应用过渡,而不是添加类,现在它非常流畅。

【讨论】:

    猜你喜欢
    • 2013-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-26
    相关资源
    最近更新 更多