前言:原本这篇文章是打算6号书写出来的,但是基于某些私人原因,希望能够通过这篇文章尽可能的将事件讲解的更加详细和通俗易懂,因此,多花了一天时间,不多说了,接下来对“事件”来一个较为详细的介绍。
欢迎大家互相学习交流。独行冰海
需要了解事件的什么?
对于事件来讲,首先,我们需要了解这样几个概念:事件;事件处理程序;事件类型;事件流;事件冒泡;事件捕获;事件对象;事件方面的性能优化(事件委托、移除事件处理程序);常见的浏览器兼容问题。
事件的概念
事件:指的是文档或者浏览器窗口中发生的一些特定交互瞬间。我们可以通过侦听器(或者处理程序)来预定事件,以便事件发生的时候执行相应的代码。
事件处理程序
事件处理程序:我们用户在页面中进行的点击这个动作,鼠标移动的动作,网页页面加载完成的动作等,都可以称之为事件名称,即:click、mousemove、load等都是事件的名称。响应某个事件的函数则称为事件处理程序,或者叫做事件侦听器。
接下来我们用一段代码来再说明一下上面这两个抽象的概念,具体解释见代码注释:
事件-独行冰海
理解事件的基本概念
<script><br> var main = document.getElementById('main');<br> // Click here はイベントの名前であり、ブラウザ ウィンドウでクリックが発生した瞬間です。 on という単語は実際にはクリック イベントに応答できるようにするため、onclick はイベント ハンドラーと呼ばれます。次のコードでは、ハンドラー (onclick) を通じてメイン要素のクリックを予約し、クリックが発生すると関数内のコードが実行されます (ダイアログ ボックスが表示されます)。 <br> main.onclick = function(){<br>alert('Click here!');<br> }<br></script>
イベント ハンドラーについては、初期の開発から現在に至るまで、経験がいくつか変化しました。回。
イベントハンドラーの名前は「on」で始まるため、クリックイベントのハンドラーはonclickです。当初、HTML イベント ハンドラーが使用されていました。つまり、要素 (div など) でサポートされる各イベントは、対応するイベント ハンドラー (つまり、タグの属性) と同じ名前の HTML 属性を使用して指定できました。 、この属性の値は、実行できる JavaScript コードです。例:
イベント - 氷の海でひとり < /head>
HTML イベント ハンドラー
もちろん、 onclick="" で関数を呼び出すこともできます。
しかし、どの方法を使用しても、HTML イベント ハンドラーの多くの問題が露呈します。
まず第一に、HTML コード ドメインと JavaScript コードは密接に結合されており、互いに分離されていないため、更新時に異常が発生します。そしてコードの維持の難しさ。
2 番目に、イベント ハンドラーのスコープ チェーンを拡張すると、ブラウザーごとに異なる結果が生じます。
3つ目は、関数を呼び出す方法を使わず、例のようにコードを直接記述すると、コードの汎用性が低くなり、サイト全体のコード量が多くなり、汎用性も悪くなります。それを抽出して関数に保存すると、別の問題に直面することになります。関数が定義されていないが、HTML コードと CSS コードがロードされており、ユーザーがクリックしても、まったく応答がありません。
上記の問題に基づいて、人々は徐々にイベント ハンドラーを改良し、この時点で DOM0 レベルのイベント ハンドラーが登場しました。 (第4世代WEBブラウザで登場)
DOMレベル0のイベントハンドラはどのようなものですか?実際、これは次の例のような最も一般的に使用されるイベント バインディングです:
< ; title>イベント - 氷の海に一人
DOM レベル 0 イベント ハンドラー
<script> DOM0 レベルのイベント ハンドラーが公開されて以来、さまざまなユーザーによって広く使用されていますが、同じ種類の複数のイベントを同じ要素/タグにバインドしたい場合に問題が発生します。たとえば、上記の場合、p タグは 3 つのクリック イベントをバインドします)、これは許可されていません。次に、この時点で、DOM2 レベルのイベント ハンドラーである別の種類のイベント ハンドラーが登場しました。DOM2 レベルでは、イベント ハンドラーの指定 (つまりバインド) と削除の操作をそれぞれ処理する 2 つの基本メソッドが定義されています。 () およびremoveEventListener()、IE9+、FireFox、Safari、Chrome、および Opera はすべて DOM2 レベルのイベント ハンドラーをサポートしています。 IE8 の場合、IE 独自のイベント ハンドラー、2 つの類似したメソッド、attachEvent() と detachEvent() が使用されます。 <br/>具体的なコード例は以下の通りです: (addEventListenerを例に2つの記述方法を示します)<br/><!doctype html><br/><html><br/><head><br/> <meta charset="UTF-8" > <br/> <title>イベント - 氷の海で一人</title><br/></head><br/><body><br/> <p id='btn'>DOM0 レベル イベント ハンドラー</p><br/>< ; /body><br/><script><br/> var btn = document.getElementById('btn');<br/> btn.addEventListener("click", test, false);<br/> function test(){<br/> alert(this.innerHTML);<br/> }<br/></script>
事件-独行冰海
DOM0级事件处理程序
<script><br/> var btn = document.getElementById('btn');<br/> btn.addEventListener("click", function(){<br/> alert(this.innerHTML); <br/> }, false);<br/></script>
addEventListener()和removeEventListener()中的第三个参数,表示的是在哪个事件阶段进行事件处理,如果是false,则指的是冒泡阶段;如果是true,则指的是捕获阶段。
在事件方面,IE与FF存在着一系列的兼容问题,具体问题可查看博文《IE浏览器与FF火狐浏览器在事件上的兼容问题》
关于如何创建一个兼容全部浏览器的事件侦听器,我们在下一篇博文《跨浏览器的事件处理函数——处理DOM2级事件兼容 》当中再做详细的介绍和代码示范。
事件类型
之前在课程的讲解当中,我们把事件分为了三大类,分别是一般事件、表单事件和页面事件。当前我们可以再做细分:
UI事件:如load、unload、error、resize、scroll、select、DOMActive,是用户与页面上的元素交互时触发的。
焦点事件:如blur、DOMFocusIn、DOMFocusOut、focus、focusin、focusout,在元素获得或失去焦点的时候触发,这些事件当中,最为重要的是blur和focus,有一点需要引起注意,这一类事件不会发生冒泡!
鼠标与滚轮事件:如click、dblclick、mousedown、mouseenter、mouseleave、mousemove、mouseout、mouseover、mouseup,是当用户通过鼠标在页面执行操作时所触发的。
滚轮事件:mousewheel(IE6+均支持)、DOMMouseScroll(FF支持的,与mousewheel效果一样)。是使用鼠标滚轮时触发的。
文本事件:textInput,在文档中输入文本触发。
键盘事件:keydown、keyup、keypress,当用户通过键盘在页面中执行操作时触发。
合成事件:DOM3级新增,用于处理IME的输入序列。所谓IME,指的是输入法编辑器,可以让用户输入在物理键盘上找不到的字符。compositionstart、compositionupdate、compositionend三种事件。
变动事件:DOMsubtreeModified、DOMNodeInserted、DOMNodeRemoved、DOMAttrModified、DOMCharacterDataModified等,当底层DOM结构发生变化时触发。IE8-不支持。
变动名称事件:指的是当元素或者属性名变动时触发,当前已经弃用!
对于事件的基本类型,随着HTML5的出现和发展,又新增了HTML5事件、设备事件、触摸事件、手势事件等各种事件,在后面我们再详细介绍。
事件流
事件流:描述的是从页面中接收事件的顺序。
IE与原来的NetScape(网景),对于事件流提出的是完全不同的顺序。IE团队提出的是事件冒泡流;NetScape的事件流是事件捕获流。
事件冒泡
事件冒泡:表示的是,事件开始的时候由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。
事件捕获
事件捕获:表示的是,事件开始的时候由最不具体的节点接收,然后逐级向下传播到最具体的节点。
来看一个实例:
事件-独行冰海
如果单击了p标签,那么,如果是事件冒泡流的事件流机制,则click事件将按照如下顺序进行执行:p —— div —— body —— html —— document。
如果采用捕获流的事件流机制,则click事件的执行顺序为:document —— html —— body —— div —— p
对于冒泡流的事件流机制,存在如下的兼容问题:
<=IE5.5 p -> div -> body -> document
>=IE6.0 p -> div -> body -> html -> document
>=Mozilla 1.0 p -> div -> body -> html -> document -> window
欢迎大家互相学习交流。独行冰海
事件对象
事件对象:在触发DOM上的某个事件的时候,会产生一个事件对象event,而在这个对象当中会包含着所有与事件有关的信息。我们书写如下基本代码:
事件-独行冰海
理解事件的基本概念
<script><br/> var main = document.getElementById('main');<br/> main.onclick = function(event){<br/> console.log(event);<br/> }<br/></script>
使用console.log打印出的结果如下图。
JavaScript事件 详细讲解 - 独行冰海 - 独行冰海
其中有两个信息,我们最为常用,分别是type和target。
type表示的是被触发事件的类型;
target表示的是事件的目标。
其他信息,如:
bubbles:表示事件是否冒泡
cancelable:表示是否可以取消事件的默认行为
currentTarget:表示事件处理程序当前正在处理事件的那个元素
defaultPrevented:表示是否调用了preventDefault()
detail:表示的是与事件相关的细节信息
eventPhase:调用事件处理处理程序的阶段:1表示捕获阶段、2表示处于目标、3表示冒泡阶段
在其中还有一些其他信息,在此就不再一一列举了。
事件方面性能优化
谈一谈事件方面如何优化性能——事件委托和事件处理程序的移除
在JavaScript代码当中,添加到页面中的事件越多,页面的性能也就越差。导致这一问题的原因主要有:
每个函数都是对象,都会占用内存。内存中对象越多,性能也就越差。
必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间。
为了进行页面的性能优化,因此我们会采用两种方法,就是上面提到的——事件委托和事件处理程序的移除。
事件委托
很多人问我,什么时候使用事件委托,其实,简单来说,当时一个页面事件处理程序比较多的时候,我们通常情况下会使用它。
事件委托主要利用了事件冒泡,只指定一个事件处理程序,就可以管理一个类型的所有事件。例如:我们为整个一个页面制定一个onclick事件处理程序,此时我们不必为页面中每个可点击的元素单独设置事件处理程序(onclick)。还是,看一个例子。
效果:点击不同的元素执行不同的操作。
不使用事件委托:
事件-独行冰海
左
1
2
3
右
<script><br/> var left = document.getElementById('left');<br/> var first = document.getElementById('first');<br/> var second = document.getElementById('second');<br/> var third = document.getElementById('third');<br/> var right = document.getElementById('right');<br/> left.addEventListener("click", function(){<br/> alert('点击的是左这个字,执行相关操作'); <br/> }, false);<br/> first.addEventListener("click", function(){<br/> alert('要执行第一个序号对应的相关操作'); <br/> }, false);<br/> second.addEventListener("click", function(){<br/> alert('要执行第二个序号对应的相关操作'); <br/> }, false);<br/> third.addEventListener("click", function(){<br/> alert('要执行第三个序号对应的相关操作'); <br/> }, false);<br/> right.addEventListener("click", function(){<br/> alert('点击的是右这个字,执行相关操作'); <br/> }, false);<br/></script>
不难看出,我们使用了5个事件侦听器,每设置一个就需要绑定一个。
使用事件委托:
事件-独行冰海
左
1
2
3
右
<script><br/> var control = document.getElementById('control');<br/> control.addEventListener("click", function(e){<br/> ) // 注、IE8- は考慮されませんすべてのブラウザに対応したイベント処理手順を書きたい場合は、次のブログ投稿を確認してください <br/> var target = e.target <br/> // ここで switch ステートメントを使用します。IF を使用して判断することもできます <br/> Switch ( target.id; ) {<br/> Case "left": {<br/> alt ('単語を左にクリックして、関連する操作を実行');<br/> Break;<br/> }<br/> : { <br/> alert('3 番目のシリアル番号に対応する関連操作を実行するには');<br/> Break; ');<br/>ブレーク;<br/> }<br/> }<br/> }, false);<br/></script>
いわゆるイベント委任を簡単に要約します。イベントを要素の親や祖先、さらにはページにバインドし、そのイベントを使用してリスクを負います。バブルの基本原理は、イベント ターゲット オブジェクトを検出し、関連する操作を実行することです。利点は次のとおりです:
イベント ハンドラーの数が大幅に減り、ページ上でイベント ハンドラーを設定する時間が短縮されます (DOM 参照が減ります。つまり、上記では ID を使用してタグを取得し、必要な検索操作とDOM の引用はさらに少ないです)。
Document (注: 上記の例はドキュメントにバインドされていませんが、親 div にバインドされています。最も推奨されるのはドキュメントにバインドすることです) オブジェクトにはすぐにアクセスでき、ページのライフサイクル中にアクセスできます イベントを追加ハンドラはいつでも実行できるため、DOMContentLoaded またはロード イベントを待つ必要はありません。言い換えれば、クリック可能な要素がページ上に表示されている限り、対応する機能がすぐに備えられます。
ページ全体が占めるメモリ領域が少なくなり、全体的なパフォーマンスが向上します。
イベント ハンドラーの削除
イベント ハンドラーが要素に割り当てられるたびに、実行中のブラウザー コードと、ページの操作を強化する JavaScript コードとの間に接続が確立されます。接続数もページの実行速度に直接影響します。したがって、古い「null イベント ハンドラー」がメモリ内に存在すると、Web アプリケーションでメモリとパフォーマンスの問題が発生します。
では、「空のイベント ハンドラー」はいつ登場するのでしょうか?
ドキュメント内の要素にイベントがあります。この要素は一部の DOM ノード操作 (removeChild、replaceChild などのメソッド) によって削除されますが、DOM ノード上のイベントは削除されません。
innerHTML はページの特定の部分を置き換えます。ページの元の部分にはイベントがあり、削除されません。
ページのアンロードが原因で、イベント ハンドラーがメモリ内でスタックします。
解決策:
イベント委任を適切に使用します。
関連する操作を実行する場合は、まずイベントを削除してから、DOM ノードを削除します。ページがアンロードされる前に、onunload イベントを通じてすべてのイベント ハンドラーを削除します。