手动触发触摸事件

34

我已经搜索了30分钟,但没有找到解决方案。

我想在一个元素上触发一个touchstart事件。

这将触发touchstart事件:

var e = document.createEvent('MouseEvent');

e.initMouseEvent("touchstart", true, true, window, 1, screenX, screenY, clientX, clientY,
    ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);

target.dispatchEvent(e);

请注意,变量是由我的函数定义的

但这里有一个问题。 event 对象没有 touches 属性。因此像这样的代码将无法工作:

var touch = e.touches[0];

有没有办法手动触发一个touchstart事件(它应该在安卓 >=4.0和启用触摸的Chrome [DevTools]上工作)?

请注意,我不想使用任何类似jQuery的框架。使用jQuery可以轻松地在元素上创建touchevent ;)


1
仅为了保持清醒,你为什么需要生成一个事件? - Halcyon
好的,假设我有一个容器。这个容器里面有很多隐藏的子容器。当我触摸这个容器时,一个子容器会变得可见,并且只要我触摸容器,我就应该能够通过移动手指来移动子容器。因此,当我触摸容器时,应该在子容器上创建一个“touchstart”事件。 - AndreM96
1
这听起来应该很容易做到,而无需伪造事件。如果您的模型知道容器依赖性,您可以从单个原始事件控制所有内容。 - Halcyon
1
嗯,这有点复杂,我不能按照你的方式做:/ 我必须伪造事件... - AndreM96
5个回答

25
根据W3C(万维网联盟)的规定
var e = document.createEvent('TouchEvent');

那么,请同时更改


e.initMouseEvent();

to

e.initTouchEvent();

由于你创建了一个touchstart事件。

W3C链接中提到:

一些用户代理实现了initTouchEvent方法作为TouchEvent接口的一部分。当此方法可用时,脚本可以使用它来初始化TouchEvent对象的属性,包括其TouchList属性(可以使用从createTouchList返回的值进行初始化)。initTouchEvent方法尚未标准化,但是它可能以某种形式出现在未来的规范中。

因此,你可能需要采用e.initUIEvent('touchstart', true, true);
此外,官方规范还指出,TouchList对象是可选的,并且可以使用createTouchList方法手动创建。要将touch添加到该列表中,您必须调用createTouch方法,在其中传递所有坐标等参数:

6.1 方法
#createTouch 创建具有指定属性的Touch对象。 参数 | 类型 | 可为空 | 可选 | 描述 view | WindowProxy | ✘ | ✘ | target | EventTarget | ✘ | ✘ | identifier| long | ✘ | ✘ | pageX | long | ✘ | ✘ | pageY | long | ✘ | ✘ | screenX | long | ✘ | ✘ | screenY | long | ✘ | ✘ | 返回类型: Touch
#createTouchList 创建由零个或多个Touch对象组成的TouchList对象。调用此方法而不带参数会创建一个没有任何对象且长度为0(零)的TouchList。
参数 | 类型 | 可为空 | 可选 | 描述 touches | Touch | ✘ | ✔ | 返回类型: TouchList

如果这不起作用,您可以尝试以下内容:

var e = document.createEvent('UIEvent');
e.initUIEvent();

应该可以正常工作,毕竟比createEvent('MouseEvent')更合理...
但是为了测试目的,为什么不打开您的Chrome控制台并检查模拟触摸事件,并覆盖用户代理到Android 4(Ctrl + Shift + j>单击右下角的齿轮图标,然后选择“覆盖”,您将找到所有需要的设置)

由于触摸事件在标准化方面还有很长的路要走,因此touches属性尚未只读(是否?),因此您可以使用此快速修复程序(OP使用并获得期望的结果)。

var e = document.createEvent('TouchEvent');
e.touches = [{pageX: pageX, pageY: pageY}];

我认为(如果不是这种情况,我无法相信)这比以下方式更快:

e.touches = e.createTouchList(
    e.createTouch(window, target, 0, pageX, pageY, screenX, screenY)
);

首先,非常感谢您的回答! :) 我也尝试过那个方法,但是它没有起作用... createEvent('TouchEvent') 没有很好的文档说明。 :/ 在 Chrome 中,我得到了这个错误:Uncaught Error: NotSupportedError: DOM Exception 9。而我的问题中提到的 [DevTools] 是指我启用了开发工具触摸功能。 ;) - AndreM96
2
@AndreM96:找到了:TouchList对象是可选的,你需要使用createTouchListcreateTouch方法手动创建一个Touch对象。 - Elias Van Ootegem
谢谢!那个方法可行。我找到了一个简单的解决方法,现在我用的是:e.touches = [{pageX: pageX, pageY: pageY}];(其中 e 是创建的事件)。但你的解决方案肯定更好! - AndreM96
2
@AndreM96:我不会这么说,如果传递一个对象字面量同样有效,那么你的解决方案可能是更好的选择。对象字面量便宜快速,而DOM庞大、反直觉且经常缓慢,因此我将编辑我的答案并包括你的解决方法。 - Elias Van Ootegem
1
@EliasVanOotegem,不是针对你个人,我并不是说你错了。只是因为我感觉太忙了,无法适当地更新答案,所以留下评论,希望对那些找到这个答案的人有所帮助。 - Georgii Ivankin
显示剩余3条评论

20

我知道这个问题已经有答案了,但是我也曾为此问题苦苦搜寻,而被接受的答案并不适用于我的情况。最终,我找到的解决方案非常简单,且在各种浏览器中都得到了支持:

var e = new Event('touchstart');
target.dispatchEvent(e);

就是这样。再简单不过了。


1
目标是什么? - scord
1
@scord target 是你想要分派事件的元素。 - Georgii Ivankin
不幸的是,由于当前浏览器的支持水平,这似乎是最合理的解决方案,尽管不太健壮。只需创建一个通用事件,并手动填充您需要的所有属性,就好像它是一个“真正的”触摸事件一样。 - Georgii Ivankin
你如何设置触摸事件的坐标? - Kevin He
@KevinHe target 定义了将接收事件的元素的坐标。 - jFrenetic
"dispatchEvent" 未定义。 - ScottyBlades

5
我想出了这个解决方案(JavaScript原生),适合我使用。
var el = document.getElementById('myDivId');
// desktop
el.click();

// mobile
if (window.matchMedia("(max-width: 768px)").matches) {
        // createEvent(), event.initEvent() are Depricated see Ref: [enter link description here][1]
        // var event = document.createEvent("Event"); 
        // event.initEvent("touchstart", false, true);
        // event.initEvent("touchend", false, true);
        // So the solution is:
        var event1 = new Event('touchstart');
        var event2 = new Event('touchend'); 
        el.dispatchEvent(event1); 
        el.dispatchEvent(event2);
  }

5

在2019年,我们可以使用TouchEventTouch

Touch是一项试验性技术。

例如,

const touch = new Touch({
  identifier: "123",
  target: target,
});

const touchEvent = new TouchEvent("touchstart", {
  touches: [touch],
  view: window,
  cancelable: true,
  bubbles: true,
});

target.dispatchEvent(touchEvent);

我创建了代码片段。试试它的简单易用性。


在 Chrome 上出现错误:无法设置仅具有 getter 的 #<TouchEvent> 的 touches 属性。 - user889030
1
@user889030,你能分享一下你的代码吗?我的工作示例在https://jsfiddle.net/3qubaek0/。 - Chase Choi
@ChaseChoi,谢谢你的fiddle,它工作得很好。看起来我的代码有问题,我根据你的fiddle进行了更新,现在它可以正常工作了。非常感谢。 - user889030
@ChaseChoi,如果您不介意的话,我能否与您分享我的代码?我正在努力解决一个网页画布问题,虽然在jsfiddle片段中演示时应该可以正常工作,但我无法触发它。我已经苦恼了一周,但是还是不知道为什么它不起作用:( - user889030
@user889030 当然,但我不确定我能否修复它。 - Chase Choi
显示剩余2条评论

-5
我们可以这样触发:
$playBtn.bind((is_touch_device) ? 'touchstart' : 'click', playfunction);

3
请查看 JavaScript 标签的简短描述:“除非还包括框架/库的标签,否则预期会得到纯 JavaScript 的答案”。只需将鼠标悬停在其上即可。没有 jQ 标签,也没有 jQ 的答案...... - Elias Van Ootegem
1
我刚刚更新了我的问题。是的,我不想使用任何框架。;) - AndreM96

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接