CSS转换后的Android 4 Chrome触摸事件测试问题 [英] Android 4 Chrome hit testing issue on touch events after CSS transform

查看:304
本文介绍了CSS转换后的Android 4 Chrome触摸事件测试问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了CSS变换和触摸事件命中测试的问题。这只能在Android 4的Chrome(稳定版和测试版)中为我重现。 iOS Safari,以及具有触摸仿真的Chrome桌面都看起来工作正常。

I'm having issues with the combination of CSS transforms and touch event hit testing. This only reproduces for me in Chrome on Android 4 (stable and beta). iOS Safari, as well as Chrome desktop with touch emulation both appear to be working fine.

我几乎肯定这是一个错误,所以我想我'主要是在这里寻找解决方法。

I'm almost positive this has to be a bug, so I think I'm mostly looking for workarounds here.

问题是,触摸的命中测试似乎只适用于元素在变换之前的位置,而不是最终位置。您可以在我的jsfiddle上看到一个示例(仅适用于Android 4 Chrome):

The issue is that hit testing for touch only seems to work for where the element was before the transform, not the final position. You can see an example on my jsfiddle (only on Android 4 Chrome):

jsfiddle: http://jsfiddle.net/LfaQq/
全屏: http://jsfiddle.net/LfaQq/embedded/result/

jsfiddle: http://jsfiddle.net/LfaQq/ full screen: http://jsfiddle.net/LfaQq/embedded/result/

如果您将蓝色方块拖动到屏幕的下半部分,快速回到顶部。现在,如果您尝试从页面的上半部分再次拖动,则不会触摸任何触摸。触摸事件甚至不会触发元素。但是,如果你试图触摸元素的底部,它工作正常。然后,您可以尝试从底部向上移动,并观察击中测试不再在底部工作,但在顶部工作。

If you drag the blue box half way down the screen and release it will snap back to the top. Now, if you try dragging from the top half of the page again, no touch will register. The touch events aren't even fired on the element. However, if you attempt to touch the bottom of the element, it works fine. You can then try moving it up from the bottom, and observing that hit testing no longer works on the bottom, but works on the top.

这是我如何处理事件:

function handleTouch(e) {

    console.log("handle touch")

    e.preventDefault();

    switch(e.type){
        case 'touchstart':
            console.log("touchstart");
            touchOriginY = e.targetTouches[0].screenY;
            break;
        case 'touchmove':
            console.log("touchmove");
            el.innerHTML = e.targetTouches[0].screenY;
            var p = e.targetTouches[0].screenY - touchOriginY;
            el.style[TRANSFORM] = 'translate3d(0,' + p + 'px' + ',0)';
            break;
        case 'touchcancel':
            console.log("touchcancel");
            // Fall through to touchend
        case 'touchend':
            //console.log("touchend");
            //el.style[TRANSITION] = '.4s ease-out';
            el.style[TRANSFORM] = 'translate3d(0,0,0)';
            break;
    }

}

el.addEventListener('touchstart', handleTouch);
el.addEventListener('touchend', handleTouch);
el.addEventListener('touchmove', handleTouch);
el.addEventListener(TRANSITION_END, function(e) {
    console.log("transition end")
    el.style[TRANSITION] = '';
});

我对touchmove中的transforms没有任何问题,因为那些不是新的触摸

I don't have any problems with the transforms in touchmove, as those aren't new touches to be detected anyways.

有任何建议吗?

推荐答案

基本上,元素的命中目标是在浏览器的布局传递过程中记录的。每次你设置innerHTML,浏览器将重新布局,最后一次这是完成,是在touchend事件引发之前。有几种方法:

Essentially the hit targets for an element is recorded during a layout pass by the browser. Each time you set innerHTML, the browser will relayout and the last time this is done, is before the touchend event is fired. There are a couple of ways around it:

选项1:您可以在body元素上设置触摸处理程序,并检查触摸事件的目标,看看它是否触摸红色块。

OPTION 1: You can set a touch handler on the body element and check the target of touch event to see if it is touching the red block. Tip of the cap to Paul Lewis for this approach.

http://jsfiddle.net/FtfR8/5/

var el = document.body;
var redblock = $('.splash-section');

function handleTouch(e) {

    console.log("handle touch")
    if(e.target != redblock) {
        return;
    }

    ....

选项2:文档上的空触摸回调似乎也解决了问题 - 根据一些链接的错误报告,这导致命中测试在主线程上完成,这是对性能的命中,但它正确计算命中目标。

OPTION 2: Set an empty touch callback on the document seems to fix the problem as well - according to some of the linked bug reports, this causes the hit testing to be done on the main thread which is a hit on performance but it properly calculates the hit targets.

http://jsfiddle.net/LfaQq/2 /

document.body.addEventListener('touchstart', function(){});

选项3:在转换结束后设置innerHTML,以强制转发:

OPTION 3: Set innerHTML after the transition has ended to force a relayout:

el.addEventListener(TRANSITION_END, function(e) {
    console.log("trans end - offsettop:" + el.offsetTop);
    el.style[TRANSITION] = '';
    el.innerHTML = 'Relayout like a boss!';
});

我在这里创建了一个错误报告,Rick Byers链接到一个相关的错误与额外的信息: https://code.google.com / p / chromium / issues / detail?id = 253456& thanks = 253456& ts = 1372075599

I've created a bug report here and Rick Byers has linked to a related bug with additional info: https://code.google.com/p/chromium/issues/detail?id=253456&thanks=253456&ts=1372075599

这篇关于CSS转换后的Android 4 Chrome触摸事件测试问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆