3.6 模仿用户操作
有时候,即使某个事件没有真正发生,但如果能执行绑定到该事件的代码将会很方便。例如,假设我们想让样式转换器在一开始时处于折叠状态。那么,可以通过样式表来隐藏按钮,或者在$(document).ready()
处理程序中调用.hide()
方法。不过,还有一种方法,就是模拟单击样式转换器,以触发我们设定的折叠机制。
通过.trigger()
方法就可以完成模拟事件的操作,如代码清单3-23所示。
代码清单3-23
$(document).ready(function() {
$('#switcher').trigger('click');
});
这样,随着页面加载完成,样式转换器也会被折叠起来,就好像是被单击了一样。结果如图3-10所示。
如果我们想向禁用JavaScript的用户隐藏一些内容,以实现优雅降级,那么这就是一种非常合适的方式。
图 3-10
.trigger()
方法提供了一组与.on()
方法相同的简写方法。当使用这些方法而不带参数时,结果将是触发操作而不是绑定行为,如代码清单3-24所示。
代码清单3-24
$(document).ready(function() {
$('#switcher').click();
});
响应键盘事件
作为另一个例子,我们还可以向样式转换器中添加键盘快捷方式。当用户输入每种显示样式的第一个字母时,可以让页面像响应按钮被单击一样作出响应。要实现这种功能,需要先了解键盘事件,键盘事件与鼠标事件稍有不同。
键盘事件可以分为两类:直接对键盘按键给出响应的事件(keyup
和keydown
)和对文本输入给出响应的事件(keypress
)。输入一个字母的事件可能会对应着几个按键,例如输入大写的X要同时按Shift和X键。虽然各种浏览器的具体实现有所不同(毫不奇怪),但有一条实践经验还是比较可靠的:如果想知道用户按了哪个键,应该侦听keyup
或keydown
事件;如果想知道用户输入的是什么字符,应该侦听keypress
事件。对于这里想要实现的功能而言,我们只想知道用户什么时候按下了D、N或L键,因而就要使用keyup
。
接下来,需要确定哪个元素应该侦听这个事件。相对于可以通过鼠标指针确定事件目标的鼠标事件而言,这个细节就没有那么明显了。事实上,键盘事件的目标是当前拥有键盘焦点的元素。元素的焦点可能会在几种情况下转移,包括单击鼠标和按下Tab键。并非所有元素都可以获得焦点,只有那些默认情况下具有键盘驱动行为的元素,如表单字段、链接,以及指定了tabIndex
属性的元素才可以获得焦点。
对于眼前的例子来说,哪个元素获得焦点其实并不重要,我们只想让转换器在用户按下某个键时能够有所反应。这一次,又可以利用事件冒泡了——因为可以假设所有键盘事件最终都会冒泡到document
元素,所以可以把keyup
事件直接绑定到该元素。
最后,需要在keyup
处理程序被触发时知道用户按下了哪个键。此时可以检查相应的事件对象,事件对象的.which
属性包含着被按下的那个键的标识符。对于字母键而言,这个标识符就是相应大写字母的ASCII值。因此,可以为字母和相应的按钮创建一个对象字面量。在用户按下某个键时,可以查找它的标识符是否在这个对象里,如果在则触发单击事件,参见代码清单3-25。
代码清单3-25
$(document).ready(function() {
var triggers = {
D: 'default',
N: 'narrow',
L: 'large'
};
$(document).keyup(function(event) {
var key = String.fromCharCode(event.which);
if (key in triggers) {
$('#switcher-' + triggers[key]).click();
}
});
});
这样,按下这三个键中的任何一个,都会模拟鼠标对相应按钮的单击——前提是键盘事件没有被某些特性(例如Firefox的“在输入时搜索文本”功能)所截取。
除了使用.trigger()
模拟单击外,下面我们再深入一步,看一看怎样把相关代码提取到一个函数中,以便更多处理程序(click
和keyup
)可以调用它。尽管在本例中没有必要这样做,但这种技术确实有利于消除冗余代码,参见代码清单3-26。
代码清单3-26
$(document).ready(function() {
//在样式转换器按钮上启用悬停效果
$('#switcher').hover(function() {
$(this).addClass('hover');
}, function() {
$(this).removeClass('hover');
});
//让样式转换器能够扩展和折叠
var toggleSwitcher = function(event) {
if (!$(event.target).is('button')) {
$('#switcher button').toggleClass('hidden');
}
};
$('#switcher').on('click', toggleSwitcher);
//模拟一次单击,以便开始时处理折叠状态
$('#switcher').click();
//setBodyClass()用于修改页面样式
//样式转换器的状态也会被更新
var setBodyClass = function(className) {
$('body').removeClass().addClass(className);
$('#switcher button').removeClass('selected');
$('#switcher-' + className).addClass('selected');
$('#switcher').off('click', toggleSwitcher);
if (className == 'default') {
$('#switcher').on('click', toggleSwitcher);
}
};
//开始的时候先选中switcher-default按钮
$('#switcher-default').addClass('selected');
//映射键码和对应的按钮
var triggers = {
D: 'default',
N: 'narrow',
L: 'large'
};
//当按钮被单击时调用setBodyClass()
$('#switcher').click(function(event) {
if ($(event.target).is('button')) {
var bodyClass = event.target.id.split('-')[1];
setBodyClass(bodyClass);
}
});
//当按下相应按键时调用setBodyClass()
$(document).keyup(function(event) {
var key = String.fromCharCode(event.keyCode);
if (key in triggers) {
setBodyClass(triggers[key]);
}
});
});
最后这次修改整合了本章前面所有的代码示例。我们把整块代码都挪到了$(document).ready()
处理程序中,代码看起来没有那么冗长了。