【问题标题】:JQuery click() on a div button won't firediv 按钮上的 JQuery click() 不会触发
【发布时间】:2014-11-25 10:13:09
【问题描述】:

我试图模拟用户对我无法控制的代码的网站的点击。我试图与充当按钮的 div 交互的元素。

<div role="button" class="c-T-S a-b a-b-B a-b-Ma oU v2" aria-disabled="false" style="-webkit-user-select: none;" tabindex="0">
    Generate
</div>

与元素关联的事件监听器(根据 Chrome 的检查器)是:

我只是想点击按钮:

var button = $('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2')
button.click()

...但什么也没发生。选择器有效,通过以下方式验证:

alert($('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2').length); // alerts "1"

我已经尝试了所有事件处理程序的排列

button.trigger('click');
button.mouseover().mousedown().mouseup()
button.trigger('mouseover', function() { button.trigger('mousedown', function() { button.trigger('mouseup'); });  });

...但还是什么都没有。如何模拟对这个 div 的点击?

如果不清楚,我是在尝试模拟点击这个div并触发原函数,而不是在元素上定义新的点击函数。

更新

其中许多答案确实确实单击了按钮,但不会产生与手动单击按钮相同的结果。所以看来问题不一定是点击按钮本身,而是模拟一个真正的点击。

【问题讨论】:

  • 使用 jQuery,总是让你的选择器成为第一个嫌疑人。在假设之前检查它实际上是在寻找元素。运行 - alert($('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2').length); - 它给你 0 还是 1?如果是前者,则找不到元素。
  • 我已经证实这不是问题所在,但这是可靠的建议。
  • 你试过使用触发器$('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2').trigger('click');
  • OK,接下来,在点击事件回调中,添加一个alert什么的。会火吗?
  • .click().trigger('click')的快捷方式

标签: javascript jquery html css simulation


【解决方案1】:

我制作了一个FIDDLE 来模拟您的“不可点击”按钮。那里的蓝色 div 附加了与您在问题中显示的相同的 eventListeners。到处玩,结果如下:

1) 让我们先获取 DOM 元素:

var button = document.getElementsByClassName('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2')[0];

2) 该页面不包含 jQuery。所以那里的所有 eventListeners 都由native .addEventListener() 附加。如果使用 jQuery 触发事件,它只会触发 jQuery 附加的事件,而不触发原生附加的事件。这意味着:

$(button).trigger('mousedown'); // this doesn't work
button.dispatchEvent(new Event('mousedown')); // this should work

3) 正如 Scimonster 所指出的,没有附加点击事件监听器。这意味着:

$(button).trigger('click'); // doesn't work anyway, see 2)
// next works, but has no visible result on the page,
// because there is no click-handler to do anything:
button.dispatchEvent(new Event('click'));

4) 当鼠标按钮上升时触发点击事件。当使用mouseup-event 时,它看起来像点击。在小提琴中,mouseup 使红色 div 可见。您可以尝试通过在代码中添加这一行来触发 mouseup 事件:

button.dispatchEvent(new Event('mouseup')); // "works", but has no visible result

mouseup-handler 被mouseover- 和mouseout-events “隐藏”,第一个附加它,后者删除它。这样,当鼠标悬停在按钮上时,mouseup 只有一个结果。我假设你的谷歌页面做了类似的事情来覆盖点击事件。

5) 你应该尝试什么:

首先以原生方式触发一些单个事件:

button.dispatchEvent(new Event('eventName'));

如果没有给出可用的结果,请使用一些合理的事件组合:

button.dispatchEvent(new Event('mouseover'));
button.dispatchEvent(new Event('mousedown'));
// or:
button.dispatchEvent(new Event('mousedown'));
button.dispatchEvent(new Event('mouseup')); // or: .....

有很多方法可以组合事件,因此单个事件不会做任何事情,但只有正确的组合才有效。

编辑根据您的调查来源的邀请,我发现了两种方法:

1) 按钮本身没有附加事件监听器。该按钮包含在&lt;a&gt;-tag 中。此标记是按钮的父级,其属性jsaction 的值告诉&lt;a&gt; 具有clickfocusmousedown 的侦听器。直接定位它有效:

button.parentElement.dispatchEvent(new Event('click'));

2) 如果您想单击按钮本身,您必须触发一个事件,该事件使 DOM 冒泡以到达具有单击处理程序的元素。但是当使用new Event('name') 创建事件时,其bubbles-property 默认为false没有想到这一点是我的错。。所以以下直接作用于按钮:

button.dispatchEvent(new Event('click', {bubbles: true}));

编辑 2 深入研究该页面上发生的事情产生了一个可用的结果:

已发现该页面负责事件的鼠标指针位置和正确顺序,可以区分是人还是机器人/脚本触发事件。因此,此解决方案使用 MouseEvent - 包含 clientXclientY 属性的对象,该对象保存事件触发时指针的坐标。

对元素的自然“点击”始终按给定顺序触发四个事件:mouseovermousedownmouseupclick。为了模拟自然行为mousedownmouseup 被延迟。为了方便起见,所有步骤都包含在一个函数中 它模拟 1)在其左上角输入元素,2)稍后在元素中心单击。详情见cmets。

function simulateClick(elem) {
    var rect = elem.getBoundingClientRect(), // holds all position- and size-properties of element
        topEnter = rect.top,
        leftEnter = rect.left, // coordinates of elements topLeft corner
        topMid = topEnter + rect.height / 2,
        leftMid = topEnter + rect.width / 2, // coordinates of elements center
        ddelay = (rect.height + rect.width) * 2, // delay depends on elements size
        ducInit = {bubbles: true, clientX: leftMid, clientY: topMid}, // create init object
        // set up the four events, the first with enter-coordinates,
        mover = new MouseEvent('mouseover', {bubbles: true, clientX: leftEnter, clientY: topEnter}),
        // the other with center-coordinates
        mdown = new MouseEvent('mousedown', ducInit),
        mup = new MouseEvent('mouseup', ducInit),
        mclick = new MouseEvent('click', ducInit);
    // trigger mouseover = enter element at toLeft corner
    elem.dispatchEvent(mover);
    // trigger mousedown  with delay to simulate move-time to center
    window.setTimeout(function() {elem.dispatchEvent(mdown)}, ddelay);
    // trigger mouseup and click with a bit longer delay
    // to simulate time between pressing/releasing the button
    window.setTimeout(function() {
        elem.dispatchEvent(mup); elem.dispatchEvent(mclick);
    }, ddelay * 1.2);
}

// now it does the trick:
simulateClick(document.querySelector(".c-T-S.a-b.a-b-B.a-b-Ma.oU.v2"));

该函数不会模拟给定任务不需要的真实鼠标移动

【讨论】:

  • 感谢您提供的信息丰富的回答。虽然我理解您的观点,并且您的 Fiddle 使用此技术按预期工作,但似乎此页面上可能发生了其他事情,我尝试过的任何 dispatchEvent 排列都未能在相关页面上产生相同的结果。我已经尝试在所有可能的位置使用焦点事件将鼠标悬停/向下/向上。不知道还能尝试什么
  • @coneybeare :( 抱歉,我自己也想不通了。我从来没有听说过让元素免受事件影响的方法。
  • 明天我将在这个问题上获得赏金(最快的 SO 让我这样做)所以如果您确实想尝试深入挖掘以帮助我解决这个令人困惑的问题,实际的“生成”页面上的按钮可能还有更多内容:security.google.com/settings/security/apppasswords
  • @coneybeare 我从不想拥有一个谷歌帐户,但现在我有了。我发现这个问题很有趣,以至于我等不及赏金了。查看我的 EDIT 并尝试自己:
  • 我们看的是同一个按钮吗?我链接到的页面上的按钮显示“生成”并且没有被锚标签包裹。在查看此页面之前,您需要在此新测试帐户上启用 2 因素身份验证。但是,按照您的指示,我尝试在带有气泡的 Generate 按钮上发送鼠标悬停、鼠标按下和鼠标向上事件:真正的选项......什么都没有。我也尝试过“点击”它。
【解决方案2】:

我为此创建了一个JS Fiddle,它工作正常。我用过以下

$('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2').click(function(){
    alert("clicked");
});
$('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2').click();// This will trigger click event programatically

【讨论】:

  • 这只是绑定了一个新的点击处理程序。我正在尝试模拟点击,而不是改变它的动作。
  • @coneybeare ,是的,我已经尝试使用第二行“.click();”,它在页面加载时被调用,并且工作正常。不知道我是否误解了你的目的!
  • 如前所述,它不能准确地模拟手动点击相关页面。
  • 当您调用“.click()”时,它会执行程序点击,我想,这就是您面临的问题,对吗?
【解决方案3】:

我实际上尝试了您提供的链接并且它有效。页面上没有jquery,所以必须通过native方法。

var click= document.createEvent("MouseEvents");
click.initMouseEvent("click", true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);

document.getElementsByClassName('c-T-S a-b a-b-B')[0].dispatchEvent(click)

【讨论】:

  • 确保你在上面的代码中给出了正确的类名......实际存在于 DOM 中的那个(即首先在 dom 中搜索正确的类名)......让我知道你是否仍然有什么问题..
  • 因此,当我运行它时,它会在控制台中返回 true,但不会出现预期的结果......这意味着页面上什么也没有发生,而真正的点击会完成我试图模拟的事情。
【解决方案4】:

$('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2').trigger('click'); 完成任务 - 触发点击事件。

.trigger() :执行附加到匹配元素的所有处理程序和行为 对于给定的事件类型。

http://api.jquery.com/trigger/

$('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2').on('click', function() {
   alert( $( this ).text() );
});

$('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2').trigger('click');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div role="button" class="c-T-S a-b a-b-B a-b-Ma oU v2" aria-disabled="false" style="-webkit-user-select: none;" tabindex="0">
    Generate
</div>

【讨论】:

  • 是的,这显示了新的JS行为,但我需要触发原始行为,而不是新功能
  • 我正在尝试模拟点击,而不是在元素上定义新功能。
  • $('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2').trigger('click');正是这样做的。 - 模拟点击。 Onlcick 处理程序和警报仅用于演示。
  • 不,问题的重点在于 $('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2').trigger('click');不会触发对该元素的点击。
  • 它确实触发了我回答中 sn-p 中的点击。因此,如果它在您的页面上不起作用,则您的问题不在 trigger() 中
【解决方案5】:

从您发布的事件处理程序的图像来看,click 不是其中之一。以编程方式触发点击与自然触发点击不同。此处不触发鼠标进入/离开/按下事件。

【讨论】:

  • 是的,我明白了,但我试过 button.mouseover().mousedown().mouseup() 也没有成功
  • 当你直接调用这些事件时不会触发它们?
  • 他们没有。这是一个谷歌页面,所以他们可能有额外的机制在发挥 idk
  • 哦,我应该知道的。没有人给出如此疯狂的类名。 :P 他们可能还有其他古怪的事情正在发生。
  • 我已经看到谷歌之前(在地图 api 中)创建了一些意外事件,因此您可能正在寻找需要触发的自定义事件
猜你喜欢
  • 2019-11-29
  • 1970-01-01
  • 2012-10-10
  • 1970-01-01
  • 1970-01-01
  • 2015-06-08
  • 1970-01-01
  • 2012-11-20
  • 1970-01-01
相关资源
最近更新 更多