关于html:javascript高级程序设计读书笔记九

43次阅读

共计 8440 个字符,预计需要花费 22 分钟才能阅读完成。

最近一个多月真是忙到飞起啊,活脱脱把美少女变成了国宝,终于告一段落,留给我的,仍然是无处安放的,魅力 (黑眼圈) 啊~
话不多说,先啃为敬 ^_^


第 13 章 事件

JavaScript 与 HTML 之间的交互式通过事件实现的。
事件,就是文档或浏览器窗口中产生的一些特定的交互霎时。

事件流—事件冒泡

IE 的事件流叫做事件冒泡,即事件开始时由最具体的元素 (文档中嵌套档次最深的那个节点) 接管,而后诸暨向上流传到较为不具体的节点 (文档)。
比方一个 <body> 标签中只蕴含一个 <div> 元素的页面,如果你点击了页面中的 <div>, 那么这个 click 事件会依照如下程序流传:
(1)<div>
(2)<body>
(3)<html>
(4)document
也就是说,click 事件首先在 <div> 元素上产生,而这个元素就是咱们点击的元素。
而后,click 事件沿 DOM 树向上流传,在每一级节点上都会产生,直至流传到 document 对象。
下图完满的展现了工夫冒泡的过程。

事件流—事件捕捉

事件捕捉的思维是不太具体的节点应该更早接管到事件,而最具体的节点应该最初接管到事件。
事件捕捉的用意在于在事件达到预约指标之前捕捉它。以下面冒泡的例子,单击 <div> 元素就会以下列程序触发 click 事件
(1) document
(2) <html>
(3) <body>
(4) <div>
在事件捕捉过程中,document 对象首先接管到 click 事件,而后事件沿 DOM 树顺次向上,始终流传到事件的理论目标,即 <div> 元素。如下图:

事件流—DOM 事件流

“DOM2 级事件 ” 规定的事件流包含三个阶段:事件捕捉阶段、处于指标阶段和事件冒泡阶段。
首先产生的是事件捕捉,为截获事件提供了机会。而后是理论的指标接管到事件。最初一个阶段是冒泡阶段,能够在这个阶段对事件做出响应。

事件处理程序

事件就是用户或浏览器本身执行的某种动作。诸如 click、load 和 mouseover,都是事件的名字。而响应某个事件的函数就叫做事件处理程序(或事件监听器)。
事件处理程序的名字以 ”on” 结尾,因而 click 事件的事件处理程序就是 onclick,load 事件的事件处理程序就是 onload。为事件指定处理程序的形式有好几种。

事件处理程序——HTML 事件处理程序

事件处理程序中的代码在执行时,有权拜访全局作用域中的任何代码。
这样指定事件处理程序具备一些独到之处。首先,这样会创立一个封装着元素属性值的函数,这个函数中有一个局部变量 event, 也就是事件对象
<input type="button" value="Click Me" onclick="alert(event.type)"> // 输入 "click"
通过 event 变量,能够间接拜访事件对象,你不必本人定义它,也不必从函数的参数列表中读取。在这个函数外部,this 值等于事件的指标元素,例如:
<input type="button" value="Click Me" onclick="alert(event.type)"> // 输入 "Click Me"

事件处理程序——DOM0 级事件处理程序

每个元素(包含 window 和 document)都有本人的工夫处理程序属性,这些属性通常全副小写,例如 onclick,将这种属性的值设置为一个函数,就能够指定事件处理程序。

var btn = document.getElementById("myBtn");
btn.onclick = function(){alert(this.id);    //"myBtn"
}
btn.onclick = null;      // 删除事件处理程序
事件处理程序——DOM2 级事件处理程序

“DOM2 级事件 ” 定义了两个办法,用于解决指定和删除事件处理程序的操作:addEventListener()和 removeEventListener()。
所有 DOM 节点中都蕴含这两个办法,并且它们都承受 3 个参数:要解决的事件名、作为事件处理程序的函数和一个布尔值。
最初这个布尔值参数如果是 true, 示意在捕捉阶段调用事件处理程序;如果是 false, 示意在冒泡阶段调用事件处理程序。

var btn = document.getElmentById("myBtn");
btn.addEventListener("click",function(){alert(this.id);
},false);   // 该事件会在冒泡阶段被触发
btn.addEventListener("click",function(){alert("Hello world!");
},false);

应用 DOM2 级办法增加事件处理程序的次要益处是能够增加多个事件处理程序。
下面的例子为按钮增加了两个事件处理程序,这两个事件处理程序会依照增加它们的程序触发,因而首先会显示元素的 ID,其次会显示 ”Hello world!” 音讯。
通过 addEventListener()增加的事件处理程序只能应用 removeEventListener()来移除;移除时传入的参数与增加处理程序时应用的参数雷同。这也意味着通过 addEventListener()增加的匿名函数将无奈移除。就像下面的例子一样。

事件处理程序——IE 事件处理程序

IE 实现了与 DOM 中相似的两个办法:attachEvent()和 detachEvent()。这两个办法承受雷同的两个参数:事件处理程序名字与事件处理程序函数。
要应用 attachEvent()为按钮增加一个事件处理程序,能够应用以下代码。

var btn = document.getElementById("myBtn");
btn.attachEvent("onclick",function(){alert("Clicked");
});

留神,attachEvent()的第一个参数是 ”onclick”,而非 DOM 的 addEventListener()办法中的 ”click”。

在 IE 中应用 attachEvent()与应用 DOM0 级办法的次要区别在于事件处理程序的作用域。在应用 DOM0 级办法的状况下,事件处理程序会在其所属元素的作用域内运行;在应用 attachEvent()办法的状况下,事件处理程序会在全局作用域中运行,因袭 this 等于 window。
var btn = document.getElementById(“myBtn”);
btn.attachEvent(“onclick”, function(){

alert(this === window);     //true

});
在编写跨浏览器的代码时,牢记这一区别十分重要。
与 addEventListener()相似,attachEvent()办法也能够用来为一个元素增加多个事件处理程序。
与 DOM 办法不同的是,这些事件处理程序不是以增加它们的程序执行,而是以相同的程序被触发。
应用 attachEvent()增加的事件能够通过 detachEvent()来移除,条件是必须提供雷同的参数。与 DOM 办法一样,这也意味着增加的匿名函数将不能被移除。

事件对象——DOM 中的事件对象

兼容 DOM 的浏览器会将一个 event 对象传入到事件处理程序中。无论指定事件处理程序时应用什么办法(DOM0 级或 DOM2 级), 都会传入 event 对象。

var btn = document.getElementById("myBtn");
btn.onclick = function(event){alert(event.type);       //"click"
};
btn.addEventListener("click", function(event) {alert(event.type);       //"click"
}, false);

event 对象蕴含与创立它的特定事件无关的属性和办法。触发的事件类型不一样,可用的属性和办法也不一样。所有的事件都会有下表列出的成员。

在事件处理程序外部,对象 this 始终等于 currentTarget 的值,而 target 则只蕴含事件的理论指标。
如果间接将事件处理程序制订给了指标元素,则 this、currentTarget 和 target 蕴含雷同的值。

var btn = document.getElementById("myBtn");
btn.onclick = function(event){alert(event.currentTarget === this);     //true
    alert(event.target === this);       //true
}

要阻止特定事件的默认行为,能够应用 preventDefault()办法。
例如,链接的默认行为就是在被单击时会导航到其 href 个性指定的 URL。如果你想阻止链接导航这一默认行为,那么通过链接的 onclick 事件处理程序能够勾销它。

var link = document.getElementById("myLink");
link.onclick = function(event) {event.preventDefault();
}

只有 cancelable 属性设置为 true 的事件,才能够应用 preventDefault()来勾销其默认行为。
另外,stopPropagation()办法用于立刻进行事件在 DOM 档次中的流传,即勾销进一步的事件捕捉或冒泡。
例如,间接增加到一个按钮的工夫处理程序能够调用 stopPropagation(),从而防止触发注册在 document.body 下面的事件处理程序。

var btn = document.getElementById("myBtn");
btn.onclick = function(event){alert("Clicked");
    event.stopPropagation();};
document.body.onclick = function(event) {alert("body clicked");
}

对于下面例子,如果不调用 stopPropagation(),就会在单击按钮时呈现两个正告框,可是因为 click 事件基本不会流传到 document.body,因而就不会触发注册在这个元素上的 onclick 事件处理程序。

事件对象的 eventPhase 属性,能够用来确定事件以后正位于事件流的哪个阶段。
如果是在捕捉阶段调用的事件处理,那么 eventPhase 等于 1;
如果事件处理程序处于指标对象上,则 eventPhase 等于 2;
如果是在冒泡阶段调用的事件处理程序,eventPhase 等于 3.
这里要留神的是,只管“处于指标”产生在冒泡阶段,但 eventPhase 依然始终等于 2。

var btn = 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 始终都是相等的。
只有在事件处理程序执行期间,event 对象才会存在;一旦事件处理程序执行实现,event 对象就会被销毁。

事件类型

Web 浏览器中可能产生的事件有很多类型。

  • UI 事件,当用户与页面上的元素交互时触发;
  • 焦点事件,当元素取得或失去焦点时触发;
  • 鼠标事件,当应用鼠标滚轮时触发;
  • 文本事件,当在文档中输出文本时触发;
  • 键盘事件,当用户通过键盘在页面上执行操作时触发;
  • 合成事件,当为 IME 输出字符时触发;
  • 变动事件,当底层 DOM 构造发生变化时触发。
UI 事件

UI 事件指的是那些不肯定与用户操作无关的事件。

  • load:当页面齐全加载后在 window 下面触发,当所有框架都加载结束时在框架集下面触发,当图像加载结束时在 <img> 元素下面触发,或者当嵌入的内容加载结束时在 <ocject> 元素下面触发。
  • unload:当页面齐全卸载后在 window 下面触发,当所有框架都卸载后在框架下面触发,或者当嵌入的内容卸载结束后在 <object> 元素下面触发。
  • error:当产生 javascript 谬误时在 window 下面触发,当无奈加载图像时在 <img> 元素下面触发,当无奈加载嵌入内容时在 <object> 元素下面触发,或者当有一或多个框架无奈加载时在框架集下面触发。
  • select:当窗口或框架的大小变动时在 window 或框架下面触发。
  • resize:当窗口或框架的大小变动时在 window 或框架下面触发。
  • scroll:当用户滚动带滚动条的元素中的内容时,在该元素下面触发。<body> 元素中蕴含所加载页面的滚动条。
焦点事件

焦点事件会在页面取得或失去焦点时触发。利用这些事件并与 document.hasFocus()办法及 document.activeElement 属性配合,能够通晓用户在页面上的行踪。

  • blur:在元素失去焦点时触发。这个事件不会冒泡,所有浏览器都反对它。
  • focus:在元素取得焦点时触发。这个事件不会冒泡,所有浏览器都反对它。
鼠标与滚轮事件
  • click:在用户单击主鼠标按钮或者按下回车键时触发。
  • 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. 鼠标按钮
只有在主鼠标按钮被单击时才会触发 click 事件,因而检测按钮的信息并不是必要的。但对于 mousedown 和 mouseup 事件来说,则在其 event 对象存在一个 button 属性,示意按下或开释的按钮。
DOM 的 button 属性可能有如下 3 个值:0 示意主鼠标按钮,1 示意两头的鼠标按钮(鼠标滚轮按钮),2 示意次鼠标按钮。
4. 触摸设施
ios 和 Android 设施的实现十分特地,因为这些设施没有鼠标。

  • 不反对 dblclick 事件。双击浏览器窗口会放大画面,而且没有方法扭转该行为。
  • 轻击可单击元素会触发 mousemove 事件。如果此操作会导致内容变动,将不再有其余事件产生;如果屏幕没有因而变动,那么会顺次产生 mousedown、mouseup 和 click 事件。轻击不可单击的元素不会触发任何事件。
  • mousemove 事件也会触发 mouseover 和 mouseout 事件。
  • 两个手指放在屏幕上且页面随手指挪动而滚动时会触发 mousewheel 和 scroll 事件。
键盘与文本事件

有 3 个键盘事件,简述如下。

  • keydown:当用户按下键盘上的任意键时触发,而且如果按住不放的话,会反复触发此事件。
  • keypress:当用户按下键盘上的字符键时触发,而且如果按住不放的话,会反复触发此事件。
  • keyup:当用户开释键盘上的键时触发。
触摸与手势事件 - 触摸事件

touchstart:当手指触摸屏幕时触发;即便曾经有一个手指放在了屏幕上也会触发。
touchmove:档收视在屏幕上滑动时间断地触发。在这个事件产生期间,调用 preventDefault()能够阻止滚动。
touchend:当手指从屏幕上移开时触发。
touchcancel:当零碎进行跟踪触摸时触发。
以上这几个事件都会冒泡,也都会勾销。

触摸与手势事件 - 手势事件

ios2.0 中的 Safari 还引入了一组手势事件。当两个手指触摸屏幕时就会产生手势,手势通常会扭转显示项的大小,或者旋转显示项。

  • gesturestart:当一个手指曾经按在屏幕上而另一个手指又触摸屏幕时触发。
  • gesturechange:当触摸屏幕的任何一个手指的地位发生变化时触发。
  • gestureend:当任何一个手指从屏幕下面移开时触发。

内存和性能——事件委托
对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就能够治理某一类型的所有事件。例如,click 事件会始终冒泡到 document 档次。
如果可行的话,也能够思考为 document 对象增加一个事件处理程序,用以解决页面上产生的某种特定类型的事件。长处如下:

  • document 对象很快就能够拜访,而且能够在页面生命周期的任何时点上为它增加事件处理程序(毋庸期待 DOMContentLoaded 或 load 事件)。换句话说,只有可单击的元素出现在页面上,就能够立刻具备适当的性能。
  • 在页面中设置事件处理程序所需的工夫更少。只增加一个事件处理程序所需的 DOM 援用更少,所花的工夫也更少。
  • 整个页面占用的内存空间更少,可能晋升整体性能。

最适宜采纳事件委托技术的事件包含 click、mousedown、mouseup、keydown、keyup 和 keypress。尽管 mouseover 和 mouseout 事件也冒泡,但要适当解决它们并不容易,而且常常须要计算元素的地位。(因为当鼠标从一个元素移到其子节点时,或者当鼠标移出该元素时,都会触发 mouseout 事件。)

小结
事件是将 Javascript 与网页分割在一起的次要模式。“DOM3 级事件”标准和 HTML5 定义了常见的大多数事件。即便有标准定义了根本事件,但很多浏览器依然在标准之外实现了本人的专有事件,从而为开发人员提供更多把握用户交互的伎俩。

  • 在应用事件时,须要思考如下一些内存与性能方面的问题
  • 有必要限度一个页面中事件处理程序的数量,数量太多会导致占用大量内存,而且也会让用户感觉页面反馈不够灵活。
  • 建设在事件冒泡机制之上的事件委托技术,能够无效地缩小事件处理程序的数量。
  • 建设在浏览器卸载页面之前移除页面中的所有事件处理程序。

事件是 Javascript 中最重要的主题之一,深刻了解事件的工作机制以及它们对性能的影响至关重要。

好啦,事件就大略记到这里啦~

正文完
 0