$(document).ready()是jQuery基于页面加载执行任务的一种主要方式。但并不是唯一,原生的window.onload也可实现相同效果。虽然二者具有类似效果,但它们在触发操作的时间上存在微妙差异,这种差异只有在加载的资源多到一定程度时才会体现出来。当文档完全下载到浏览器中时,会触发window.onload。这意味着页面上的全部元素对JavaScript而言都是可操作的,这种情况对编写功能性的代码非常有利,因为无需考虑加载次序。另一方面,通过$(document).ready()注册的事件处理程序,则会在DOM完全就绪并可使用时调用。虽然这也意味着所有元素对脚本而言都是可以访问的,但是,却不意味着所有关联的文件都已下载完毕为保证JavaScript代码执行以前页面已经应用了样式,最好是在 <head>元素中把 <link rel="stylesheet"> 标签和 <style> 标签放在 <script> 标签前一般来说,$(document).ready()要优于使用onload,但必须要明确,因为支持文件可能还没有加载完成,所以类似图像的高度宽度属性此时不一定有效。如果需要访问这些属性,可能就得选择实现一个onload(或使用jQuery为load事件设置处理程序)。这两种机制和平共存我们既可以在HTML标记中指定该函数:<body οnlοad="doStuff();">也可在JavaScript中指定:window.onload = doStuff;这两种方式都会在页面加载完成后执行这个函数。但后者的优点在于,它能使行为更清晰地从标记中分离出来。注意,这里在将函数指定为处理程序时,省略了(),只用了函数名。如果带(),函数会被立即调用;没有,函数名就只是函数的标识符或函数引用,可用于在将来再调用.在只有一个函数的情况下,这样做没问题。但假设又定义了第2个函数: function doOtherStuff() { //执行另外一种任务...... } 也可将它指定为基于页面的加载来运行:window.onload = doOtherStuff;然而,这次指定的函数会取代刚才指定的第1个函数。因为.onload属性一次只能保存对一个函数的引用,所以不能在现有行为基础上再增加新行为。通过$(document).ready()机制能很好地解决这个问题。每次调用$(document).ready()都会向内部的行为队列中添加一个新函数,当页面加载完成后,所有函数都会被执行。而且,这些函数会按照注册它们的顺序依次执行(通过window.onload虽然也可注册多个函数,但却不能保证按顺序执行)。在某些情况下,可能有必要在同一个页面中使用多个JavaScript库。由于很多库都使用$标识符,因此就需一种方式来避免名称冲突。为解决这个问题,jQuery提供了一个jQuery.noConflict(),调用该方法可以把对$标识符的控制权让渡还给其他库: <script src="prototype.js"></script> <script src="jquery.js"></script> <script> jQuery.noConflict(); </script> <script src="myscript.js"></script> 首先,包含jQuery之外的库(这里是Prototype)。然后,包含jQuery库,取得对$的使用权。接着,调用.noConflict()方法让出$,以便将控制权交还给Prototype。这样就可在自定义脚本中使用2个库——但是,在需要使用jQuery方法时,必须记住要用jQuery而不是$来调用。在这种情况下,还有一个在.ready()中使用$的技巧。传递给它的回调函数可以接收一个参数——jQuery对象本身。利用这个参数,可以重新命名jQuery为$,而不必担心造成冲突: jQuery(document).ready(function($) { //在这里,可以正常使用! }); 或者,也可以使用刚刚介绍的简写语法: jQuery(function($) { //使用$的代码 });
$(document).ready(function() { $('#switcher-large').on('click', function() { $('body').addClass('large'); });}); 这里的全部操作就是绑定一个事件。多次调用.on()也没有任何问题,即可按需为同一事件追加更多行为。但这不是最优雅或最有效的方式允许多个元素响应单击事件的一种策略叫做事件捕获(事件捕获和事件冒泡是“浏览器大战”时期分别由Netscape和微软提出的2种相反的事件传播模型)。在事件捕获过程中,事件首先会交给最外层的元素,接着再交给更具体的元素。另一种相反的策略叫做事件冒泡。即当事件发生时,会首先发送给最具体的元素,在这个元素获得响应机会之后,事件会向上冒泡到更一般的元素。毫不奇怪,不同的浏览器开发者最初采用的是不同的事件传播模型。因而,最终出台的DOM标准规定应该同时使用这2种策略:首先,事件从一般到具体元素逐层捕获,然后再通过冒泡返回DOM树的顶层。而事件处理程序可注册到这个过程中的任何一个阶段。为确保跨浏览器的一致性,也为了让人容易理解,jQuery始终会在模型的冒泡阶段注册事件处理程序。因此,我们总是可以假定最具体的元素会首先获得响应事件的机会。事件冒泡可能会导致始料不及的行为,特别是在错误的元素响应mouseover或mouseout事件的情况下。假设在我们的例子中,为<div>添加了一个mouseout事件处理程序。当用户的鼠标指针退出这个<div>时,会按照预期运行mouseout处理程序。因为这个过程发生在顶层元素上,所以其他元素不会取得这个事件。但是,当指针从<a>元素上离开时,<a>元素也会取得一个mouseout事件。然后,这个事件会向上冒泡到<span>和<div>,从而触发上述的事件处理程序。这种冒泡序列很可能不是我们所希望的。而mouseenter和mouseleave,无论是单独绑定,还是在.hover()方法中组合绑定,都可避免这些冒泡问题。在使用它们处理事件时,不用担心某些非目标元素得到mouseover或mouseout事件导致的问题。//未完成的代码$(document).ready(function() { $('#switcher').click(function() { $('#switcher button').toggleClass('hidden'); });}); 这种改变会使样式转换器的整个区域都可通过单击切换其可见性。但同时也造成一个问题,即单击按钮会在修改内容区的样式之后折叠样式转换器。导致这个问题的原因就是事件冒泡,即事件首先被按钮处理,然后又沿着DOM树向上传递,直至到达<div id="switcher">激活事件处理程序并隐藏按钮。要解决这个问题,必须访问。事件对象是一种DOM结构,它会在元素获得处理事件的机会时传递给被调用的事件处理程序。这个对象中包含着与事件有关的信息(例如事件发生时的鼠标指针位置),也提供了可以用来影响事件在DOM中传递进程的一些方法。为使用事件对象,需为函数加1个参数: $(document).ready(function() { $('#switcher').click(function(event) { $('#switcher button').toggleClass('hidden'); }); }); 注意,这里把事件对象命名为event,主要是为了让大家一看就知道是什么,不是必须这样命名。event保存事件对象。event.target保存发生事件的目标元素。事件对象的.stopPropagation() (要在IE8及更早版本中安全使用,需将事件对象的cancelBubble属性设为false(但若通过jQuery来注册所有事件处理程序,就可放心使用))可完全阻止事件冒泡。在事件的环境中完成了某些验证之后,通常会用到.preventDefault()。例如,在表单提交期间,对用户是否填写了必填字段进行检查,如果用户没有填写相应字段,就需阻止默认操作事件传播和默认操作是相互独立的2套机制,在2者任何一方发生时,都可终止另一方。如果想要同时停止事件传播和默认操作,可在事件处理程序中return false,这是对在事件对象上同时调用.stopPropagation()和.preventDefault()的一种简写方式is()与.hasClass():要测试元素是否包含某个类,可使用.hasClass()。不过,.is()更灵活,它可以测试任何选择符表达式$('#switcher').on('click', 'button', function() { var bodyClass = event.target.id.split('-')[1]; $('body').removeClass().addClass(bodyClass); $('#switcher button').removeClass('selected'); $(this).addClass('selected');});(内置的事件委托)$(document).ready(function() { $('#switcher').click(function(event) { if (!$(event.target).is('button')) $('#switcher button').toggleClass('hidden'); }); $('#switcher-narrow, #switcher-large').click(function() { $('#switcher').off('click'); });});(移除事件处理程序)$(document).ready(function() { $('#switcher').on('click.collapse', function(event) { if (!$(event.target).is('button')) $('#switcher button').toggleClass('hidden'); }); $('#switcher-narrow, #switcher-large').click(function() { $('#switcher').off('click.collapse'); });});(用命名空间使.off()更据针对性)对事件处理系统,后缀.collapse不可见$(document).ready(function() { var toggleSwitcher = function(event) { if (!$(event.target).is('button')) $('#switcher button').toggleClass('hidden'); }; $('#switcher').on('click.collapse', toggleSwitcher);});(事件的重新绑定)使用命名函数时,必须省略函数名后的()。()会导致函数被调用,而非被引用$(document).ready(function() { var toggleSwitcher = function(event) { if (!$(event.target).is('button')) $('#switcher button').toggleClass('hidden'); }; $('#switcher').on('click', toggleSwitcher); $('#switcher button').click(function() { $('#switcher').off('click', toggleSwitcher); if (this.id== 'switcher-default') $('#switcher').on('click', toggleSwitcher); });});(完整的事件解除与重新绑定)对于只需触发一次,随后立即解绑的也有一种简写方法——.one():$('#switcher').one('click', toggleSwitcher);$(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(); });});键盘事件分2类:直接对键盘按键给出响应事件(keyup和keydown)和对文本输入给出响应事件(keypress)。如果想知道用户按了哪个键,侦听keyup/keydown;输入的是什么字符,侦听keypress