如何使用JavaScript模拟按键或点击事件?

44

我编写了一个Google Chrome扩展程序,我想在其上使用的网站要求我单击或切换到文本框(因为我认为它只运行JavaScript验证“onClick”)。 我可以通过我的扩展程序获取框中的文本,使用:

document.getElementById("input1").value = 'test';

但是,当我点击提交时,它认为我没有在“input1”文本框中输入任何内容,因为我从未点击或切换到它。

有人能帮助我解决这个问题吗?

5个回答

82

模拟鼠标点击

我的猜测是网页监听的是mousedown而不是click事件(这会影响无障碍性,因为当用户使用键盘时,只触发focus和click事件,而不是mousedown)。因此,您应该模拟mousedown、click和mouseup事件(顺便说一下,这就是iPhone、iPod Touch和iPad在轻敲事件上所做的事情)。

为了模拟鼠标事件,对于支持DOM 2 Events的浏览器,您可以使用以下代码片段。对于更可靠的模拟,请使用initMouseEvent来填充鼠标位置。

// DOM 2 Events
var dispatchMouseEvent = function(target, var_args) {
  var e = document.createEvent("MouseEvents");
  // If you need clientX, clientY, etc., you can call
  // initMouseEvent instead of initEvent
  e.initEvent.apply(e, Array.prototype.slice.call(arguments, 1));
  target.dispatchEvent(e);
};
dispatchMouseEvent(element, 'mouseover', true, true);
dispatchMouseEvent(element, 'mousedown', true, true);
dispatchMouseEvent(element, 'click', true, true);
dispatchMouseEvent(element, 'mouseup', true, true);
当您触发模拟的点击事件时,浏览器实际上会触发默认操作(例如导航到链接的href或提交表单)。
在IE中,等效的代码段是这样的(未经验证,因为我没有IE)。 我认为您无法提供事件处理程序的鼠标位置。
// IE 5.5+
element.fireEvent("onmouseover");
element.fireEvent("onmousedown");
element.fireEvent("onclick");  // or element.click()
element.fireEvent("onmouseup");

模拟键盘按下和按键事件

你可以模拟键盘按下和按键事件,但是不幸的是,在Chrome浏览器中它们只会触发事件处理程序,并且不执行任何默认操作。我认为这是因为DOM 3 Events工作草案描述了这种奇怪的键盘事件顺序

  1. keydown(通常具有默认操作,例如触发click、submit或textInput事件)
  2. keypress(如果该键不只是Shift或Ctrl等修饰符键)
  3. (keydown, keypress) with repeat=true if the user holds down the button
  4. 默认的keydown操作!!
  5. keyup

这意味着在模拟键盘事件时,需要同时参考HTML5DOM 3 Events的草案,模拟浏览器本应执行的大量操作。对此我感到非常不爽。例如,以下大致是如何模拟在输入框或文本区域中按下一个键:

// DOM 3 Events
var dispatchKeyboardEvent = function(target, initKeyboradEvent_args) {
  var e = document.createEvent("KeyboardEvents");
  e.initKeyboardEvent.apply(e, Array.prototype.slice.call(arguments, 1));
  target.dispatchEvent(e);
};
var dispatchTextEvent = function(target, initTextEvent_args) {
  var e = document.createEvent("TextEvent");
  e.initTextEvent.apply(e, Array.prototype.slice.call(arguments, 1));
  target.dispatchEvent(e);
};
var dispatchSimpleEvent = function(target, type, canBubble, cancelable) {
  var e = document.createEvent("Event");
  e.initEvent.apply(e, Array.prototype.slice.call(arguments, 1));
  target.dispatchEvent(e);
};

var canceled = !dispatchKeyboardEvent(element,
    'keydown', true, true,  // type, bubbles, cancelable
    null,  // window
    'h',  // key
    0, // location: 0=standard, 1=left, 2=right, 3=numpad, 4=mobile, 5=joystick
    '');  // space-sparated Shift, Control, Alt, etc.
dispatchKeyboardEvent(
    element, 'keypress', true, true, null, 'h', 0, '');
if (!canceled) {
  if (dispatchTextEvent(element, 'textInput', true, true, null, 'h', 0)) {
    element.value += 'h';
    dispatchSimpleEvent(element, 'input', false, false);
    // not supported in Chrome yet
    // if (element.form) element.form.dispatchFormInput();
    dispatchSimpleEvent(element, 'change', false, false);
    // not supported in Chrome yet
    // if (element.form) element.form.dispatchFormChange();
  }
}
dispatchKeyboardEvent(
    element, 'keyup', true, true, null, 'h', 0, '');

我认为在IE中无法模拟按键事件。


6
我已经尝试了Chrome扩展,但它没有起作用......从创建的事件记录中显示,“which”、“charCode”和“keyCode”的值为0,而不是正确的字符/键码。有人遇到同样的问题吗? - hamczu
3
@hamczu 这个SO回答提供了解决charCode = 0问题的方法。这是一个webkit已知的bug,已经存在了大约5年时间! - tanushree
有没有Chrome扩展中调度键盘事件的解决方案? - David Da Silva Contín
1
这段代码在最新的Chrome版本中(截至2016-09-17)已经无法使用。 - Samul
2
这段代码在最新版本的Chrome中已经无法使用,截至2017-01-08,这个答案需要更新! - user4535610
显示剩余8条评论

8

您可以通过以下方式在元素上触发点击事件:

// this must be done after input1 exists in the DOM
var element = document.getElementById("input1");

if (element) element.click();

这里有个例子


我尝试了这个,但出于某种原因,该网站仍然认为我没有输入任何内容...很奇怪。 - milan
尝试其他事件,如 focuschangekeypress - Russ Cam
我发现这在Chrome(WebKit)上不起作用。HTMLAnchorElement的click属性未定义。 - Howard M. Lewis Ship
你正在使用哪个版本的Chrome浏览器以及在哪个平台上?我刚刚在Windows7上尝试访问了示例页面,使用的是15.0.874.102版本的Chrome浏览器,一切都正常。这个示例对你来说是否有效? - Russ Cam
element.click 不是一个函数。 - MrEduar

7
甚至更简单,只需使用标准现代JavaScript即可:
var first_link = document.getElementsByTagName('a')[0];
first_link.dispatchEvent(new MouseEvent('click'));
< p > < code > new MouseEvent 构造函数需要一个必须的事件类型名称,然后是一个可选的对象(至少在Chrome中)。因此,您可以设置事件的一些属性,例如:

first_link.dispatchEvent(new MouseEvent('click', {bubbles: true, cancelable: true}));

5

0

可能你正在寻找的是焦点(Focus)。通过选项卡或点击,我想你指的是将元素设为焦点。这与Russ的代码相同(抱歉,我偷了他的代码 :P),但会触发另一个事件。

// this must be done after input1 exists in the DOM
var element = document.getElementById("input1");

if (element) element.focus();

谢谢,我也尝试过这个方法,还有点击事件,但是网站仍然认为我没有输入任何内容... - milan

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