3.6 模仿用户操作

有时候,即使某个事件没有真正发生,但如果能执行绑定到该事件的代码将会很方便。例如,假设我们想让样式转换器在一开始时处于折叠状态。那么,可以通过样式表来隐藏按钮,或者在$(document).ready()处理程序中调用.hide()方法。不过,还有一种方法,就是模拟单击样式转换器,以触发我们设定的折叠机制。

通过.trigger()方法就可以完成模拟事件的操作,如代码清单3-23所示。

代码清单3-23

  1. $(document).ready(function() {
  2. $('#switcher').trigger('click');
  3. });

这样,随着页面加载完成,样式转换器也会被折叠起来,就好像是被单击了一样。结果如图3-10所示。

如果我们想向禁用JavaScript的用户隐藏一些内容,以实现优雅降级,那么这就是一种非常合适的方式。

响应键盘事件 - 图1

图 3-10

.trigger()方法提供了一组与.on()方法相同的简写方法。当使用这些方法而不带参数时,结果将是触发操作而不是绑定行为,如代码清单3-24所示。

代码清单3-24

  1. $(document).ready(function() {
  2. $('#switcher').click();
  3. });

响应键盘事件

作为另一个例子,我们还可以向样式转换器中添加键盘快捷方式。当用户输入每种显示样式的第一个字母时,可以让页面像响应按钮被单击一样作出响应。要实现这种功能,需要先了解键盘事件,键盘事件与鼠标事件稍有不同。

键盘事件可以分为两类:直接对键盘按键给出响应的事件(keyupkeydown)和对文本输入给出响应的事件(keypress)。输入一个字母的事件可能会对应着几个按键,例如输入大写的X要同时按Shift和X键。虽然各种浏览器的具体实现有所不同(毫不奇怪),但有一条实践经验还是比较可靠的:如果想知道用户按了哪个键,应该侦听keyupkeydown事件;如果想知道用户输入的是什么字符,应该侦听keypress事件。对于这里想要实现的功能而言,我们只想知道用户什么时候按下了D、N或L键,因而就要使用keyup

接下来,需要确定哪个元素应该侦听这个事件。相对于可以通过鼠标指针确定事件目标的鼠标事件而言,这个细节就没有那么明显了。事实上,键盘事件的目标是当前拥有键盘焦点的元素。元素的焦点可能会在几种情况下转移,包括单击鼠标和按下Tab键。并非所有元素都可以获得焦点,只有那些默认情况下具有键盘驱动行为的元素,如表单字段、链接,以及指定了tabIndex属性的元素才可以获得焦点。

对于眼前的例子来说,哪个元素获得焦点其实并不重要,我们只想让转换器在用户按下某个键时能够有所反应。这一次,又可以利用事件冒泡了——因为可以假设所有键盘事件最终都会冒泡到document元素,所以可以把keyup事件直接绑定到该元素。

最后,需要在keyup处理程序被触发时知道用户按下了哪个键。此时可以检查相应的事件对象,事件对象的.which属性包含着被按下的那个键的标识符。对于字母键而言,这个标识符就是相应大写字母的ASCII值。因此,可以为字母和相应的按钮创建一个对象字面量。在用户按下某个键时,可以查找它的标识符是否在这个对象里,如果在则触发单击事件,参见代码清单3-25。

代码清单3-25

  1. $(document).ready(function() {
  2. var triggers = {
  3. D: 'default',
  4. N: 'narrow',
  5. L: 'large'
  6. };
  7. $(document).keyup(function(event) {
  8. var key = String.fromCharCode(event.which);
  9. if (key in triggers) {
  10. $('#switcher-' + triggers[key]).click();
  11. }
  12. });
  13. });

这样,按下这三个键中的任何一个,都会模拟鼠标对相应按钮的单击——前提是键盘事件没有被某些特性(例如Firefox的“在输入时搜索文本”功能)所截取。

除了使用.trigger()模拟单击外,下面我们再深入一步,看一看怎样把相关代码提取到一个函数中,以便更多处理程序(clickkeyup)可以调用它。尽管在本例中没有必要这样做,但这种技术确实有利于消除冗余代码,参见代码清单3-26。

代码清单3-26

  1. $(document).ready(function() {
  2. //在样式转换器按钮上启用悬停效果
  3. $('#switcher').hover(function() {
  4. $(this).addClass('hover');
  5. }, function() {
  6. $(this).removeClass('hover');
  7. });
  8. //让样式转换器能够扩展和折叠
  9. var toggleSwitcher = function(event) {
  10. if (!$(event.target).is('button')) {
  11. $('#switcher button').toggleClass('hidden');
  12. }
  13. };
  14. $('#switcher').on('click', toggleSwitcher);
  15. //模拟一次单击,以便开始时处理折叠状态
  16. $('#switcher').click();
  17. //setBodyClass()用于修改页面样式
  18. //样式转换器的状态也会被更新
  19. var setBodyClass = function(className) {
  20. $('body').removeClass().addClass(className);
  21. $('#switcher button').removeClass('selected');
  22. $('#switcher-' + className).addClass('selected');
  23. $('#switcher').off('click', toggleSwitcher);
  24. if (className == 'default') {
  25. $('#switcher').on('click', toggleSwitcher);
  26. }
  27. };
  28. //开始的时候先选中switcher-default按钮
  29. $('#switcher-default').addClass('selected');
  30. //映射键码和对应的按钮
  31. var triggers = {
  32. D: 'default',
  33. N: 'narrow',
  34. L: 'large'
  35. };
  36. //当按钮被单击时调用setBodyClass()
  37. $('#switcher').click(function(event) {
  38. if ($(event.target).is('button')) {
  39. var bodyClass = event.target.id.split('-')[1];
  40. setBodyClass(bodyClass);
  41. }
  42. });
  43. //当按下相应按键时调用setBodyClass()
  44. $(document).keyup(function(event) {
  45. var key = String.fromCharCode(event.keyCode);
  46. if (key in triggers) {
  47. setBodyClass(triggers[key]);
  48. }
  49. });
  50. });

最后这次修改整合了本章前面所有的代码示例。我们把整块代码都挪到了$(document).ready()处理程序中,代码看起来没有那么冗长了。