Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
228 views
in Technique[技术] by (71.8m points)

javascript - JQuery click() on a div button won't fire

I am trying to emulate a user's click on a site who's code I do not control. The element I am trying to engage with a div acting as button.

<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>

The event listeners that are associated with element (according to Chrome's inspector) are:

enter image description here

And I am simply trying to click the button using:

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

... but nothing happens. The selector is valid, as verified by:

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

I have tried permutations of all the event handlers

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

... but still nothing. How can I simulate a click on this div?

In case it is not clear, I am trying to simulate a click on this div and trigger the original function, not define a new click function on the element.

UPDATE

Many of these answer do indeed click the button, but don't produce the same result as manually clicking the button. So it appears the problem is not necessarily clicking the button per se, but emulating a real click.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I have made a FIDDLE to simulate your "non-clickable" button. The blue div there has the same eventListeners attached as you have shown in your question. Playing around ended up with following results:

1) Let's get the DOM-element first:

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

2) The page doesn't include jQuery. So all eventListeners there are attached by native .addEventListener(). If you use jQuery to trigger events, it triggers only the events that are attached by jQuery, but not the native attached events. That means:

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

3) As Scimonster pointed out, there is no click-eventListener attached. That means:

$(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) The click-event fires when the mousebutton goes up. When the mouseup-event is used instead it looks like a click. In the fiddle the mouseup makes the red div visible. You may try to trigger the mouseup-event by adding this line to the code:

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

The mouseup-handler is "hidden" by the mouseover- and mouseout-events, the first attaches it and the latter removes it. That way mouseup has only a result when mouse is over the button. I assume your google-page does something similar to cover the click-event.

5) What you should try:

First trigger some single events in native way:

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

If that gives no usable results use some reasonable combinations of events:

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

There are many ways to combine events so that a single event doesn't do anything, but only the right combination works.

EDIT According to your invitation to investigate the source I found two ways:

1) The button itself has no eventListeners attached. The button is wrapped in an <a>-tag. This tag is parent of the button and its attribute jsaction 's value tells that <a> has listeners for click, focus, and mousedown. Targeting it directly works:

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

2) If you want to click the button itself you must trigger an event that bubbles up the DOM to reach an element that has a click-handler. But when creating an event with new Event('name'), its bubbles-property defaults to false. It was my bad not thinking of that.. So the following works directly on the button:

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

EDIT 2 Digging deeper in whats going on on that page yielded an usable result:

It has been found that the page takes care of the mouse-pointer position and right order of the events, probable to distinguish wether a human or a robot/script triggers the events. Therefore this solution uses the MouseEvent - object containing the clientX and clientY properties, which holds the coordinates of the pointer when the event is fired.

A natural "click" on an element always triggers four events in given order: mouseover, mousedown, mouseup, and click. To simulate a natural behaviour mousedown and mouseup are delayed. To make it handy all steps are wrapped in a function which simulates 1) enter element at it's topLeft corner, 2) click a bit later at elements center. For details see comments.

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"));

The function does not simulate the real mouse movement being unnecessary for the given task.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...