当前位置: 首页 > Web前端 > HTML

《javascript高级程序设计》读书笔记(9)

时间:2023-04-03 00:12:37 HTML

过去一个多月,忙到把一个美少女变成了国宝,终于告一段落了。留给我的还是无处可放。魅力(黑眼圈)啊~话不多说,先啃吧^_^第13章事件JavaScript和HTML的交互是通过事件实现的。事件是发生在文档或浏览器窗口中的特定交互时刻。事件流——事件冒泡IE的事件流称为事件冒泡,即事件一开始由最具体的元素(文档中嵌套层级最深的节点)接收,然后逐集向上传播到不太具体的节点(文档)。例如,标签中只有一个

元素的页面,如果点击页面中的
,点击事件将按以下顺序传播:(1)
(2)(3)(4)document也就是说,点击事件首先发生在
元素上,这个元素就是我们点击的元素。然后,单击事件向上传播DOM树并在每个节点级别上发生,直到它传播到文档对象。下图完美展示了时间冒泡的过程。EventStreaming-EventCapture事件捕获的思想是,不太具体的节点应该更早接收事件,而最具体的节点应该最后接收事件。事件捕获的目的是在事件到达预定目的地之前捕获事件。以上面的冒泡为例,点击
元素会按照以下顺序触发click事件(1)document(2)(3)(4)
在事件捕获过程中,document对象首先接收到点击事件,然后事件沿着DOM树向上传播到事件的实际目的地,即
元素。如下图所示:事件流程——DOM事件流程“DOM2级事件”规定的事件流程包括三个阶段:事件捕获阶段、目标阶段和事件冒泡阶段。首先发生的是事件捕获,它提供了拦截事件的机会。然后实际目标接收事件。最后一个阶段是冒泡阶段,可以响应事件。事件处理程序事件是由用户或浏览器本身执行的某种操作。比如click、load、mouseover都是事件的名称。响应事件的函数称为事件处理程序(或事件侦听器)。事件处理器名称以“on”开头,所以click事件的事件处理器是onclick,load事件的事件处理器是onload。有几种方法可以指定事件的处理程序。事件处理程序-HTML事件处理程序事件处理程序中的代码在执行时可以访问全局范围内的任何代码。以这种方式指定事件处理程序具有一些独特的功能。首先,这将创建一个封装元素属性值的函数。这个函数里面有个局部变量event,就是事件对象//通过事件变量输出“点击”,可以直接访问事件对象,不需要自己定义,也不需要从函数的参数列表中读取。在这个函数内部,这个值等于事件的目标元素,例如://Output"ClickMe"eventhandler——DOM0级事件处理器每个元素(包括window和document)都有自己的timehandler属性,这些属性通常都是小写的,比如onclick,这个属性的值设置为一个函数,可以指定事件处理程序。varbtn=document.getElementById("myBtn");btn.onclick=function(){警报(this.id);//"myBtn"}btn.onclick=null;//deleteeventhandlereventhandler--DOM2-leveleventhandlers“DOM2-levelevents”定义了两个处理事件处理器赋值和移除的方法:addEventListener()和removeEventListener()。这两个方法包含在所有DOM节点中,它们都接受3个参数:要处理的事件的名称、作为事件处理程序的函数和一个布尔值。如果最后一个布尔参数为真,则表示事件处理程序在捕获阶段被调用;如果为假,则表示在冒泡阶段调用了事件处理程序。varbtn=document.getElmentById("myBtn");btn.addEventListener("click",function(){alert(this.id);},false);//事件会在冒泡阶段触发btn.addEventListener("click",function(){alert("Helloworld!");},false);使用DOM2级别方法添加事件处理程序的主要好处是可以添加多个事件处理程序。上面的示例为按钮添加了两个事件处理程序,它们按添加的顺序触发,因此首先显示元素的ID,然后显示“Helloworld!”。第二个显示消息。通过addEventListener()添加的事件处理程序只能使用removeEventListener()删除;为删除传递的参数与添加处理程序时使用的参数相同。这也意味着无法删除通过addEventListener()添加的匿名函数。就像上面的例子一样。事件处理程序-IE事件处理程序IE实现了两个类似于DOM中的方法:attachEvent()和detachEvent()。两种方法都接受相同的两个参数:事件处理程序名称和事件处理程序函数。要使用attachEvent()将事件处理程序添加到按钮,可以使用以下代码。varbtn=document.getElementById("myBtn");btn.attachEvent("onclick",function(){alert("Clicked");});注意attachEvent()的第一个参数是“onclick”,而在非DOM的addEventListener()方法中是“click”。在IE中使用attachEvent()与使用DOM0级方法之间的主要区别在于事件处理程序的范围。在使用DOM0级方法的情况下,事件处理程序将在其所属元素的范围内运行;在使用attachEvent()方法的情况下,事件处理程序将在全局范围内运行,这等于window.varbtn=document.getElementById("myBtn");btn.attachEvent("onclick",function(){alert(this===window);//true});在编写跨浏览器代码时记住这一点非常重要。与addEventListener()类似,attachEvent()方法也可用于向元素添加多个事件处理程序。与DOM方法不同,这些事件处理程序不是按照它们添加的顺序执行,而是以相反的顺序触发。如果提供相同的参数,则可以使用detachEvent()删除使用attachEvent()添加的事件。与DOM方法一样,这也意味着无法删除添加的匿名函数。事件对象-DOM中的事件对象DOM兼容的浏览器将事件对象传递到事件处理程序中。无论指定事件处理程序(DOM0级别还是DOM2级别)时使用的方法如何,都会传入事件对象。类型);//“点击”};btn.addEventListener(“点击”,function(event){alert(event.type);//“点击”},false);事件对象包含与创建它的特定事件相关的属性和方法。触发的事件类型不同,可用的属性和方法也不同。所有活动的成员都列在下表中。在事件处理程序中,对象this始终等于currentTarget的值,而target仅包含事件的实际目标。如果事件处理程序直接分配给目标元素,则this、currentTarget和target包含相同的值。varbtn=document.getElementById("myBtn");btn.onclick=function(event){alert(event.currentTarget===this);//真正的警报(event.target===this);//true}要防止特定事件的默认行为,可以使用preventDefault()方法。例如,链接的默认行为是在单击时导航到其href属性指定的URL。如果您想阻止链接导航的默认行为,您可以通过链接的onclick事件处理程序取消它。varlink=document.getElementById("myLink");link.onclick=function(event){event.preventDefault();}只有cancelable属性设置为true的事件才能使用preventDefault()来取消它的默认行为。另外,stopPropagation()方法用于立即停止事件在DOM层级中的传播,即取消进一步的事件捕获或冒泡。例如,直接添加到按钮的事件处理程序可以调用stopPropagation(),从而避免触发注册在document.body上的事件处理程序。varbtn=document.getElementById("myBtn");btn.onclick=function(event){alert("Clicked");event.stopPropagation();};document.body.onclick=function(event){alert("bodyclicked");}对于上面的例子,如果不调用stopPropagation(),当按钮被调用时会出现两个警告框单击,但由于单击事件根本不会传播到document.body,因此不会触发此元素上的onclick事件处理程序中的注册。事件对象的eventPhase属性可用于确定事件当前处于事件流的哪个阶段。如果在捕获阶段调用事件处理器,则eventPhase等于1;如果事件处理程序在目标对象上,则eventPhase等于2;如果是在冒泡阶段调用的事件处理程序,则eventPhase等于3。这里需要注意的是,即使“ontarget”发生在冒泡阶段,eventPhase始终等于2。varbtn=document.getElementById("myBtn");btn.onclick=function(event){alert(event.eventPhase);//2};document.body.addEventListener("click",function(event){alert(event.eventPhase);//1},true);document.body.onclick=function(event){alert(event.eventPhase);//3};当这个例子中的按钮被点击时,第一个被执行的事件处理程序是在捕获阶段触发的在document.body中添加的处理程序,因此会弹出一个警告框显示eventPhase为1。然后会触发注册在按钮上的事件处理程序,此时的eventPhase值为2。最后触发的事件处理程序,冒泡阶段执行的添加到document.body的事件处理程序显示eventPhase值为3。当eventPhase等于2时,this.target和currentTarget总是相等的。事件对象仅在事件处理程序执行期间存在;一旦事件处理程序完成执行,事件对象就会被销毁。事件类型Web浏览器中可能会发生多种类型的事件。UI事件,当用户与页面上的元素交互时触发;焦点事件,当元素获得或失去焦点时触发;鼠标事件,在使用鼠标滚轮时触发;文本事件,在文档中输入文本时触发;键盘事件,当用户通过键盘对页面进行操作时触发;复合事件,当为IME输入字符时触发;change事件,当底层DOM结构发生变化时触发。UI事件UI事件是指不一定与用户操作相关的事件。load:在页面完全加载时在窗口上触发,在加载所有框架时在框架集上,在加载图像时在元素上,或在加载嵌入内容时在元素上触发。unload:当页面完全卸载时在窗口上触发,当所有框架都卸载时在框架上触发,或者当嵌入内容卸载时在元素上触发。error:当发生javascript错误时在窗口上触发,当无法加载图像时在元素上触发,当无法加载嵌入内容时在元素上触发,或者当一个或多个帧无法加载时触发框架集。select:当窗口或框架的大小改变时在窗口或框架上触发。resize:当窗口或框架的大小改变时在窗口或框架上触发。scroll:当用户使用滚动条滚动元素中的内容时在元素上触发。元素包含加载页面的滚动条。FocusEventsFocus事件在页面获得或失去焦点时触发。利用这些事件,配合document.hasFocus()方法和document.activeElement属性,就可以知道用户在页面上的行踪。blur:当元素失去焦点时触发。该事件不会冒泡,所有浏览器都支持。focus:当元素获得焦点时触发。该事件不会冒泡,所有浏览器都支持。鼠标和滚轮事件click:当用户单击鼠标主按钮或按下Enter键时触发。dblclick:当用户双击主鼠标按钮时触发。mousedown:当用户按下任何鼠标按钮时触发。该事件不能由键盘触发。mouseenter:当鼠标光标第一次从元素外部移动到元素边界内时触发。当光标移动到后代元素上时,此事件不会冒泡也不会触发。mouseleave:当元素上的鼠标光标移出元素边界时触发。当光标移动到后代元素上时,此事件不会冒泡也不会触发。mousemove:当鼠标指针在元素内移动时重复触发。该事件不能由键盘触发。mouseout:当鼠标指针位于一个元素上然后用户将其移至另一个元素时触发。移入的另一个元素可能位于前一个元素之外,也可能是该元素的子元素。mouseover:当鼠标指针位于一个元素之外,然后用户第一次将其移动到另一个元素的边界内时触发。mouseup:当用户释放鼠标按钮时触发。页面上的所有元素都支持鼠标事件。除mouseenter和mouseleave外,所有鼠标事件都会冒泡并可以取消,取消鼠标事件会影响浏览器的默认行为。只有在同一个元素上连续触发mousedown和mouseup事件时,才会触发click事件;如果mousedown和mouseup其中之一取消,则不会触发click事件。同理,click事件触发两次,dblclick事件只会触发一次。这四个事件的触发顺序总是如下:(1)mousedown(2)mouseup(3)click(4)mousedown(5)mouseup(6)click(7)dblclick显然click和dblclick事件都会取决于其他先前事件的触发;而mousedown和mouseup不受其他事件的影响。1.客户区的坐标位置鼠标事件都发生在浏览器视口的特定位置。此位置信息存储在事件对象的clientX和clientY属性中。它们的值表示事件发生时鼠标指针在视口中的水平和垂直坐标。2.页面坐标位置通过客户区的坐标可以知道鼠标在视口中发生的位置,页面坐标可以通过事件对象的pageX和pageY属性告诉你事件在页面的什么位置发生。换句话说,这两个属性表示鼠标光标在页面中的位置,因此坐标是从页面本身而不是视口的左边缘和上边缘计算的。当页面不滚动时,pageX和pageY的值等于clientX和clientY的值。3.屏幕坐标位置当鼠标事件发生时,不仅会有相对于浏览器窗口的位置,还会有相对于整个电脑屏幕的位置。通过screenX和screenY属性可以确定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息。4.鼠标按钮仅在单击鼠标主按钮时触发点击事件,因此不需要检测按钮的信息。但是对于mousedown和mouseup事件,在其事件对象中有一个button属性,表示按下或释放按钮。DOM的button属性可能有以下三个值:0表示鼠标主键,1表示鼠标中键(鼠标滚轮按钮),2表示辅助鼠标键。4.触摸设备ios和android设备的实现很特别,因为这些设备没有鼠标。不支持dblclick事件。双击浏览器窗口会放大,并且无法更改该行为。点击可点击元素会触发mousemove事件。如果此操作导致内容发生变化,则不会发生其他事件;如果屏幕没有相应变化,则mousedown、mouseup、click事件会依次发生。点击不可点击的元素不会触发任何事件。mousemove事件还会触发mouseover和mouseout事件。当两个手指放在屏幕上并且页面随手指移动滚动时,会触发鼠标滚轮和滚动事件。键盘事件和文本事件有3种键盘事件,下面简单介绍一下。keydown:当用户按下键盘上的任意键时触发,按住不放会重复触发该事件。keypress:当用户按下键盘上的某个字符键时触发,如果一直按住,会重复触发该事件。keyup:当用户释放键盘上的某个键时触发。触摸和手势事件——触摸事件touchstart:手指触摸屏幕时触发;即使屏幕上已经有手指,它也会被触发。touchmove:当视图在屏幕上滑动时连续触发。在此事件期间调用preventDefault()以防止滚动。touchend:当手指离开屏幕时触发。touchcancel:当系统停止跟踪触摸时触发。以上所有事件都会冒泡并被取消。TouchandGestureEvents-GestureEventsSafari在ios2.0中也引入了一组手势事件。当两个手指触摸屏幕时会产生手势,手势通常会改变显示项的大小,或者旋转显示项。gesturestart:当一个手指已经在屏幕上时,另一个手指触摸屏幕时触发。gesturechange:当任意手指触摸屏幕的位置发生变化时触发。gestureend:任意手指离开屏幕时触发。内存和性能-事件委托“事件处理程序过多”问题的解决方案是事件委托。事件委托利用事件冒泡,只指定一个事件处理程序来管理某一类型的所有事件。例如,点击事件冒泡到文档级别。如果可能,请考虑向文档对象添加事件处理程序以处理页面上发生的某些类型的事件。优点如下:文档对象可以被快速访问,事件处理程序可以在页面生命周期的任何时候添加到它(不需要等待DOMContentLoaded或加载事件)。换句话说,一旦可点击元素呈现在页面上,它就应该立即具有适当的功能。在页面中设置事件处理程序花费的时间更少。仅添加一个事件处理程序需要更少的DOM引用并花费更少的时间。整页占用更少的内存空间,提高整体性能。最适合事件委托的事件包括click、mousedown、mouseup、keydown、keyup和keypress。虽然mouseover和mouseout事件也会冒泡,但适当地处理它们并不容易,而且通常需要计算元素的位置。(因为当鼠标从一个元素移动到它的子节点时,或者当鼠标移出该元素时,mouseout事件会触发。)摘要事件是将Javascript绑定到网页的主要形式。“DOM3级别事件”规范和HTML5定义了大多数常见事件。尽管有定义基本事件的规范,但许多浏览器在规范之外实现了自己的专有事件,从而使开发人员可以更好地控制用户交互。使用事件时,需要考虑以下内存和性能问题。有必要限制页面中事件处理程序的数量。过多的事件处理器会占用大量内存,让用户感觉页面响应不够灵敏。基于事件冒泡机制的事件委托技术可以有效减少事件处理程序的数量。建立以在浏览器卸载页面之前从页面中删除所有事件处理程序。事件是Javascript中最重要的主题之一,深入了解事件的工作原理以及它们如何影响性能至关重要。好了,事件到此结束~