一:事件流
事件流描述的是从页面中接收事件的顺序,IE和Netscape提出来差不多完全相反的事件流的概念,IE事件流是事件冒泡流,Netscape事件流是事件捕获流。
事件冒泡
IE的事件流叫做事件冒泡,即事件开始时由最具体的元素(文档中嵌套最深的那个节点)接收,然后逐级向上(一直到文档);如下代码:
1
2
3
4
5
|
<div
id
=
"div"
>
<span
id
=
"span"
>
<a
id
=
"aTag"
>
事件测试
</a>
</span>
</div>
|
JS如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
|
当单击 “事件测试”文字后,那么click事件会按照如下顺序传播;
1)先打印出:点击的是a标签
2) 再打印出:点击的是span标签
3) 最后打印出:点击的是div标签
4) 最后肯定是document文档。
所有现代浏览器都支持事件冒泡。
事件捕获:
事件捕获与事件冒泡事件流正好相反的顺序,事件捕获的事件流是最外层逐级向内传播,也就是先document,然后逐级div标签 , span标签 , a标签;
上面的JS代码改成如下:
1
2
3
|
document
.
getElementById
(
"div"
)
.
addEventListener
(
'click'
,
div
,
true
)
;
document
.
getElementById
(
"aTag"
)
.
addEventListener
(
'click'
,
aTag
,
true
)
;
document
.
getElementById
(
"span"
)
.
addEventListener
(
'click'
,
span
,
true
)
;
|
第三个参数设置为true,即为捕获事件,默认为false;否则的话,事件流还是和上面的一样,因为不管是在IE还是标准浏览器下,事件冒泡浏览器都支持的。
DOM事件流
DOM2级事件规定的事件流包括三个阶段,分别是:事件捕获阶段,处于目标阶段和事件冒泡阶段。示意图就不画了,具体的可以看看书。
DOM0级事件处理程序
如下代码是DOM0级事件处理程序:
1
2
3
4
|
var
btn
=
document
.
getElementById
(
"btn"
)
;
btn
.
onclick
=
function
(
)
{
alert
(
"Clicked"
)
;
}
;
|
使用DOM0级方法指定的事件处理程序被认为是元素的方法,处理程序是在元素的作用域进行的,程序中this是引用的是当前元素。
1
2
3
4
5
|
<
div
id
=
"btn"
>
btn
<
/
div
>
var
btn
=
document
.
getElementById
(
"btn"
)
;
btn
.
onclick
=
function
(
)
{
alert
(
this
.
id
)
;
// 弹出btn
}
|
单击元素btn后,通过this.id取得元素的属性id,还可以通过this访问元素的任何属性和方法,以这种方式添加的事情处理程序在事件流的冒泡阶段处理。
也可以删除通过DOM0级方法指定的事件处理程序,只要将事件处理程序的属性值设置为null即可。
btn.onclick = null; // 删除事件处理程序;
如下JS代码改成如下:
1
2
3
4
5
|
var
btn
=
document
.
getElementById
(
"btn"
)
;
btn
.
onclick
=
function
(
)
{
alert
(
this
.
id
)
;
}
btn
.
onclick
=
null
;
|
再单击btn后,没有任何反应;
DOM2级事件处理程序
DOM2级事件定义了2个方法,用于处理指定和删除事件处理程序的操作;
addEventListener()和removeEventListener()。所有DOM节点都包含这两个方法,他们包含三个参数,第一个参数为事件类型;第二个参数为事件函数,第三个参数为布尔值,如果是true的话,说明是事件流是捕获事件,如果是false的话,那么事件流是冒泡事件;
比如如上的btn代码,我们改成如下:
1
2
3
4
|
var
btn
=
document
.
getElementById
(
"btn"
)
;
btn
.
addEventListener
(
'click'
,
function
(
e
)
{
alert
(
this
.
id
)
;
}
,
false
)
;
|
上面的点击事件是在冒泡阶段被触发,与DOM0级方法一样,这里添加的事件处理程序也是在其依副的元素作用域中运行,使用DOM2级添加事件处理程序的好处是可以添加多个事件处理程序,如下代码:
1
2
3
4
5
6
7
|
var
btn
=
document
.
getElementById
(
"btn"
)
;
btn
.
addEventListener
(
'click'
,
function
(
e
)
{
alert
(
this
.
id
)
;
}
,
false
)
;
btn
.
addEventListener
(
'click'
,
function
(
e
)
{
alert
(
"我是来测试的"
)
;
}
,
false
)
;
|
上面的代码被弹出2次对话框,而在DOM0级是不可以的;它永远是执行最后一次的。
addEventListener添加的事件只能使用removeEventListener来删除相对应的事件,那么如上的JS不能按照上面的方式来编写哦!需要给定义一个函数;如下:
1
2
3
4
|
btn
.
addEventListener
(
'click'
,
handler
,
false
)
;
function
handler
(
e
)
{
alert
(
this
.
id
)
;
}
|
可以使用如下方式对click事件删除;如下代码:
btn.removeEventListener(‘click’,handler);
上面的是在标准浏览器下处理的事件,下面我们来看看在IE下处理的事件;
IE事件处理的程序
IE实现了与DOM类似的2个方法,分别是attachEvent()和detachEvent(),这两个方法只接受2个参数,第一个参数是事件名称,第二个参数是要处理的函数;由于IE8及更早版本只支持事件冒泡,所以通过attachEvent()添加的事件处理程序会被添加到冒泡阶段;
下面是IE事件处理程序的代码如下:
1
2
3
4
|
btn
.
attachEvent
(
'onclick'
,
handler
)
;
function
handler
(
e
)
{
alert
(
this
)
;
// window
}
|
注意:attachEvent的事件名称是onclick,而addEventListener的事件名称是click,且IE中使用的attachEvent()与使用DOM0级方法的的主要区别在于事件处理程序的作用域,在使用dom0级情况下,事件处理程序在其所属元素的作用域内运行,在使用attachEvent()方法的情况下,事件处理程序在全局作用域下运行,其中的this等于window。
与addEventListener一样,attachEvent也可以注册多个点击click事件,如下代码:
1
2
3
4
5
6
|
btn
.
attachEvent
(
'onclick'
,
function
(
e
)
{
alert
(
"1"
)
;
}
)
;
btn
.
attachEvent
(
'onclick'
,
function
(
e
)
{
alert
(
"2"
)
;
}
)
;
|
但是与Dom方法不同的是,这些事件处理程序不是以添加他们的顺序执行,而是以相反的顺序触发,比如如上代码,会先弹出2,然后弹出1对话框;
使用attachEvent注册的事件只能使用detachEvent()方法来移除;
下面我们可以来编写跨浏览器的事件处理程序;代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
var
EventUtil
=
{
addHandler
:
function
(
element
,
type
,
handler
)
{
if
(
element
.
addEventListener
)
{
element
.
addEventListener
(
type
,
handler
,
false
)
;
}
else
if
(
element
.
attachEvent
)
{
element
.
attachEvent
(
"on"
+
type
,
handler
)
;
}
else
{
element
[
"on"
+
type
]
=
handler
;
}
}
,
removeHandler
:
function
(
element
,
type
,
handler
)
{
if
(
element
.
removeEventListener
)
{
element
.
removeEventListener
(
type
,
handler
,
false
)
;
}
else
if
(
element
.
detachEvent
)
{
element
.
detachEvent
(
"on"
+
type
,
handler
)
;
}
else
{
element
[
"on"
+
type
]
=
null
;
}
}
}
;
|
下面我们可以使用这个封装的函数代码来测试之前的代码了,代码改成如下所示:
1
2
3
4
|
function
handler
(
)
{
alert
(
1
)
;
}
EventUtil
.
addHandler
(
btn
,
'click'
,
handler
)
;
|
在IE或者标准浏览器下都会弹出1;如果我们需要移除click事件的话,我们可以使用如下代码:
EventUtil.removeHandler(btn,’click’,handler);
然后在标准浏览器下或者IE下点击btn元素都没有反应;
事件对象:
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息;包括导致事件的元素,事件的类型以及其他与特定事件相关的信息。我们来看看dom0级和dom2级的事件对象Event;
比如如下代码:
1
2
3
4
|
var
btn
=
document
.
getElementById
(
"btn"
)
;
btn
.
onclick
=
function
(
e
)
{
console
.
log
(
e
)
;
}
|
打印如下:
下面我们来看看最基本的成员的含义吧;如下:
属性/方法 | 类型 | 含义 |
bubbles | Boolean | 事件是否冒泡 |
cancelable | Boolean | 是否可以取消事件的默认行为 |
currentTarget | Boolean | 事件处理程序当前正在处理事件的那个元素 |
defaultPrevented | Boolean | 为true 表示已经调用了preventDefault() |
detail | Integer | 与事件相关的细节信息 |
eventPhase | Integer | 调用事件处理程序的阶段:1表示捕获阶段,2表示“处于目标”,3表示冒泡阶段 |
preventDefault() | Function | 取消事件的默认行为。如果cancelable是true,则可以使用这个方法 |
stopImmediatePropagation() | Function | 取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用 |
stopPropagation() | Function | 取消事件的进一步捕获或冒泡。如果bubbles为true,则可以使用这个方法 |
target | Element | 事件的目标 |
type | String | 被触发的事件的类型 |
view | AbstractView | 与事件关联的抽象视图。等同于发生事件的window对象 |
理解currentTarget与target
在事件处理程序内部,this始终等于currentTarget值,即currentTarget是指当前被触发或者说正在处理事件的那个元素,而target是指当前的目标元素;比如如下代码,对btn按钮触发点击事件,那么e.currentTraget指向了this,e.target也指向了this;如下代码:
1
2
3
4
5
|
var
btn
=
document
.
getElementById
(
"btn"
)
;
btn
.
onclick
=
function
(
e
)
{
console
.
log
(
e
.
currentTarget
==
this
)
;
// true
console
.
log
(
e
.
target
==
this
)
;
// true
}
|
但是如果我对document.body触发点击的话,那么e.currentTarget就指向了document.body了,那么e.target 指向与 btn那个元素了,如下代码:
1
2
3
4
5
|
document
.
body
.
onclick
=
function
(
e
)
{
console
.
log
(
e
.
currentTarget
===
document
.
body
)
;
// true
console
.
log
(
document
.
body
===
this
)
;
// true
console
.
log
(
e
.
target
===
document
.
getElementById
(
"btn"
)
)
;
//true
}
;
|
现在应该能理解currentTarget与target的区别吧!currentTarget就是指被点击的那个元素,但是target是当前点击的目标元素,如上代码,由于btn上并没有注册事件,结果click事件就冒泡到了document.body,在那里事件才得到了处理。
理解标准浏览器下的事件对象与IE下的事件对象
标准浏览器下的事件对象是event,比如btn点击后;如下代码:
1
2
3
4
5
6
7
8
9
10
|
var
btn
=
document
.
getElementById
(
"btn"
)
;
btn
.
onclick
=
function
(
)
{
console
.
log
(
event
)
;
//标准浏览器下打印事件对象
console
.
log
(
event
.
type
)
;
//'click'
}
btn
.
onclick
=
function
(
)
{
// IE下打印的事件对象window.event
console
.
log
(
window
.
event
)
;
console
.
log
(
window
.
event
.
type
)
;
// 'click'
}
|
上面的写法是在DOM0级上注册事件,如果我们在Dom2级上注册事件的话,那么就会有一个事件对象event作为参数传入事件到函数中,如下:
1
2
3
4
|
var
btn
=
document
.
getElementById
(
"btn"
)
;
EventUtil
.
addHandler
(
btn
,
'click'
,
function
(
e
)
{
console
.
log
(
e
)
;
}
)
;
|
理解特定事件的默认行为事件
在标准浏览器下,在阻止特定事件的默认行为,可以使用preventDefault()方法,比如如下,我点击一个连接,按道理是打开一个新连接窗口,但是我使用preventDefault()方法可以阻止默认行为,阻止打开新窗口;如下代码:
1
2
3
4
5
6
7
|
HTML:
<
a
href
=
"http://www.baidu.com"
id
=
"alink"
target
=
"_blank"
>打开新连接
<
/
a
>
JS如下:
var
alink
=
document
.
getElementById
(
"alink"
)
;
alink
.
onclick
=
function
(
e
)
{
console
.
log
(
e
)
e
.
preventDefault
(
)
;
}
|
就可以阻止页面进行跳转了~ 这是标准浏览器下处理方式,下面我们来看看IE是如何处理默认事件的;
IE下使用returnValue属性来取消给定事件的默认行为,只要将returnValue属性值设置为false即可,就可以阻止浏览器的默认行为,如下代码:
1
2
3
4
|
alink
.
onclick
=
function
(
)
{
console
.
log
(
window
.
event
)
window
.
event
.
returnValue
=
false
;
}
|
标准浏览器下与IE下的事件目标的区别
标准浏览器下使用e.target来指定当前被点击的目标元素,如下代码所示:
1
2
3
4
5
|
var
btn
=
document
.
getElementById
(
"btn"
)
;
btn
.
onclick
=
function
(
)
{
console
.
log
(
event
)
;
console
.
log
(
event
.
target
)
;
// 打印事件目标元素
}
|
IE下是使用event.srcElement来指定当前的目标元素,如下代码:
1
2
3
4
|
btn
.
onclick
=
function
(
)
{
console
.
log
(
event
)
;
console
.
log
(
window
.
event
.
srcElement
)
;
}
|
理解标准浏览器与IE下阻止事件传播的区别
在标准浏览器下我们可以使用stopPropagation()方法来停止事件在DOM层次中的传播,即取消事件中的冒泡或者捕获。从而避免触发注册在document.body上面的事件处理程序,如下所示:
1
2
3
4
5
6
7
8
|
var
btn
=
document
.
getElementById
(
"btn"
)
;
btn
.
onclick
=
function
(
e
)
{
alert
(
1
)
;
e
.
stopPropagation
(
)
;
}
document
.
body
.
onclick
=
function
(
)
{
alert
(
2
)
;
}
|
如上代码,如果我不使用stopPropagation()阻止冒泡事件的话,那么在页面中会先弹出1,然后弹出2,如果使用stopPropagation()方法的话,只会在页面上弹出1,就不会冒泡到body上面去;
IE下停止冒泡的话,我们可以使用cancelBubble属性,我们只要将此属性设置为true,即可阻止事件通过冒泡触发document.body中的注册事件。但是IE是不支持捕获事件的,但是stopPropagation()即支持捕获事件又支持冒泡事件的。如下代码:
1
2
3
4
5
6
7
|
btn
.
onclick
=
function
(
e
)
{
alert
(
1
)
;
window
.
event
.
cancelBubble
=
true
;
}
document
.
body
.
onclick
=
function
(
)
{
alert
(
2
)
;
}
|
如果不设置window.event.cancelBubble 为true的话,就会先弹出1,然后弹出2,如果加上的话,就只会弹出1对话框。
理解了上面的区别后,我们现在可以往EventUtil对象里面添加跨浏览器的方法了;
跨浏览器的事件对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
var
EventUtil
=
{
addHandler
:
function
(
element
,
type
,
handler
)
{
if
(
element
.
addEventListener
)
{
element
.
addEventListener
(
type
,
handler
,
false
)
;
}
else
if
(
element
.
attachEvent
)
{
element
.
attachEvent
(
"on"
+
type
,
handler
)
;
}
else
{
element
[
"on"
+
type
]
=
handler
;
}
}
,
removeHandler
:
function
(
element
,
type
,
handler
)
{
if
(
element
.
removeEventListener
)
{
element
.
removeEventListener
(
type
,
handler
,
false
)
;
}
else
if
(
element
.
detachEvent
)
{
element
.
detachEvent
(
"on"
+
type
,
handler
)
;
}
else
{
element
[
"on"
+
type
]
=
null
;
}
}
,
getEvent
:
function
(
event
)
{
return
event
?
event
:
window
.
event
;
}
,
getTarget
:
function
(
event
)
{
return
event
.
target
||
event
.
srcElement
;
}
,
preventDefault
:
function
(
event
)
{
if
(
event
.
preventDefault
)
{
event
.
preventDefault
(
)
;
}
else
{
event
.
returnValue
=
false
;
}
}
,
stopPropagation
:
function
(
event
)
{
if
(
event
.
stopPropagation
)
{
event
.
stopPropagation
(
)
;
}
else
{
event
.
cancelBubble
=
true
;
}
}
}
;
|
事件类型:
DOM3级事件规定了以下几类事件;如下:
UI事件: 当用户与页面上的元素交互时触发;
load事件:当页面加载完后(包括所有图像,所有javascript文件,css文件等外部资源),就会触发window上面的load事件,如下代码是加载图片的:
HTML代码:<img src = “event.png” id=”img”/>
JS代码如下:
1
2
3
4
5
|
var
img
=
document
.
getElementById
(
"img"
)
;
EventUtil
.
addHandler
(
img
,
'load'
,
function
(
event
)
{
var
event
=
EventUtil
.
getEvent
(
event
)
;
alert
(
EventUtil
.
getTarget
(
event
)
.
src
)
;
}
)
;
|
当图片加载完后,就会弹出图片的url地址了;
如果在创建新的img元素时,可以为其指定一个事件处理程序,以便图像加载完成后给出提示,此时,最重要的是在指定src属性之前先指定事件;如下代码所示:
1
2
3
4
5
6
7
8
9
|
EventUtil
.
addHandler
(
window
,
'load'
,
function
(
)
{
var
img
=
document
.
createElement
(
"img"
)
;
EventUtil
.
addHandler
(
img
,
'load'
,
function
(
e
)
{
e
=
EventUtil
.
getEvent
(
e
)
;
alert
(
EventUtil
.
getTarget
(
e
)
.
src
)
;
}
)
;
document
.
body
.
appendChild
(
img
)
;
img
.
src
=
"event.png"
;
}
)
;
|
在图像加载完成后,会弹出图片地址了;
同样的功能,我们可以使用DOM0级的Image对象来实现,在DOM出现之前,开发人员经常使用Image对象在客户端预加载图像,如下代码:
1
2
3
4
5
6
7
|
EventUtil
.
addHandler
(
window
,
'load'
,
function
(
)
{
var
img
=
new
Image
(
)
;
EventUtil
.
addHandler
(
img
,
'load'
,
function
(
e
)
{
alert
(
1
)
;
}
)
;
img
.
src
=
"event.png"
;
}
)
;
|
Script元素也支持load事件,但是IE8及以下不支持,在IE9+,Firefox,Opera,chrome及Safari3+都支持,以便开发开发人员确定动态加载的javascript文件是否加载完毕;比如我们动态创建script标签后,通过load事件判断动态创建的script标签是否加载完毕,代码如下:
1
2
3
4
5
6
7
8
|
EventUtil
.
addHandler
(
window
,
'load'
,
function
(
)
{
var
script
=
document
.
createElement
(
"script"
)
;
EventUtil
.
addHandler
(
script
,
'load'
,
function
(
e
)
{
alert
(
1
)
;
}
)
;
script
.
src
=
"a.js"
;
document
.
body
.
appendChild
(
script
)
;
}
)
;
|
事件委托
有了以上作为基础,事件委托应该是很简单了。什么是事件委托?对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。例如,click事件会冒泡到document层次,也就是说,我们可以为整个页面指定一个onclick事件处理程序,而不必给每个可单击的元素分别添加事件处理程序。
举个经常举的例子,比如有如下代码:
1
2
3
4
5
|
<ul
id
=
'myLink'
>
<li
id
=
'a'
>
apple
</li>
<li
id
=
'b'
>
banana
</li>
<li
id
=
'c'
>
orange
</li>
</ul>
|
需要的效果是每点击相应的<li>
选项,alert它里面的单词,或许很简单:
1
2
3
4
5
6
|
var
lis
=
document
.
getElementsByTagName
(
'li'
)
;
for
(
var
i
=
0
,
len
=
lis
.
length
;
i
<
len
;
i
++
)
{
lis
[
i
]
.
onclick
=
function
(
)
{
alert
(
this
.
innerHTML
)
;
}
;
}
|
但是如上代码绑定了三个事件,我们知道每个事件绑定都需要占用一定的内存,更糟糕的是,如果在代码执行过程中,动态地又添加了一个li,这时它没有绑定click的事件,我们还需要手动添加!这时,我们就可以用到事件委托技术:
1
2
3
4
|
var
f
=
document
.
getElementById
(
'myLink'
)
;
f
.
onclick
=
function
(
e
)
{
console
.
log
(
e
.
target
.
innerHTML
)
;
}
;
|
好吧,就是这么简单!
焦点事件:当元素获得或失去焦点时触发;
有:blur:在元素失去焦点时触发,这个事件不会冒泡,所有浏览器都支持。
foucs:在元素获得焦点时触发,这个事件不会冒泡,所有浏览器都支持。
鼠标事件:当用户通过鼠标在页面操作时触发;
- click事件:在用户单击鼠标按钮或者按下回车键触发;
- dblclick事件:在用户双击鼠标按钮时被触发;
- mousedown事件:在用户按下了任意鼠标按钮时被触发,不能通过键盘触发这个事件。
- mouseenter事件:在鼠标光标从元素外部移动到元素范围之内被触发;这个事件不冒泡;
- mousemove事件:当鼠标指针在元素内部移动时重复地触发。
- mouseout事件:用户将其移入另一个元素内被触发。
- mouseover事件:鼠标指针在元素外部,用户将移入另一个元素的边界时触发,感觉和mouseenter事件类似;
- mouseup事件:用户释放鼠标按钮时触发;
页面上所有的元素都支持鼠标事件,除了mouseenter和mouseleave,所有鼠标事件都会冒泡,也可以被取消,而取消鼠标事件将会影响浏览器的默认行为。
理解客户区坐标位置
含义是:鼠标指针在可视区中的水平clientX和垂直clientY坐标;
如下图所示:
代码如下:
1
2
3
4
|
EventUtil
.
addHandler
(
btn
,
'click'
,
function
(
e
)
{
e
=
EventUtil
.
getEvent
(
e
)
;
console
.
log
(
"可视区X轴坐标为:"
+
e
.
clientX
+
" "
+
"可视区Y轴坐标为:"
+
e
.
clientY
)
;
}
)
;
|
注意:客户区坐标位置不包含滚动条滚动的位置,因此这个位置不代表鼠标在页面上的位置;
理解页面坐标位置pageX和pageY:
pageX与pageY是指页面坐标的位置,与clientX和clientY的区别是:它包含页面滚动条的位置,如下图所示:
代码如下:
1
2
3
4
|
EventUtil
.
addHandler
(
btn
,
'click'
,
function
(
e
)
{
e
=
EventUtil
.
getEvent
(
e
)
;
console
.
log
(
"页面X轴坐标为:"
+
e
.
pageX
+
" "
+
"页面Y轴坐标为:"
+
e
.
pageY
)
;
}
)
;
|
在页面没有滚动条的情况下,pageX与clientX相等,同理pageY与clientY相等。
但是IE8及更早的版本不支持pageX与pageY,不过我们可以使用客户区坐标(client,clientY)和滚动坐标计算出来;因此我们需要用到document.body(混杂模式下)或 document.documentElement(标准模式下)中的scrollLeft和scrollTop属性;
对此我们可以封装代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
EventUtil
.
addHandler
(
btn
,
'click'
,
function
(
e
)
{
e
=
EventUtil
.
getEvent
(
e
)
;
var
pageX
=
e
.
pageX
,
pageY
=
e
.
pageY
;
if
(
!
pageX
)
{
pageX
=
e
.
clientX
+
(
document
.
body
.
scrollLeft
||
document
.
documentElement
.
scrollLeft
)
;
}
if
(
!
pageY
)
{
pageY
=
e
.
clientY
+
(
document
.
body
.
scrollTop
||
document
.
documentElement
.
scrollTop
)
;
}
console
.
log
(
"页面X轴坐标为:"
+
pageX
+
" "
+
"页面Y轴坐标为:"
+
pageY
)
;
}
)
;
|
理解屏幕坐标的位置
屏幕横坐标screenX和垂直坐标screenY属性是相对于整个屏幕的。如下图所示:
如下代码测试:
1
2
3
4
|
EventUtil
.
addHandler
(
btn
,
'click'
,
function
(
e
)
{
e
=
EventUtil
.
getEvent
(
e
)
;
console
.
log
(
"屏幕X轴的坐标为:"
+
e
.
screenX
+
" "
+
"屏幕Y轴的坐标为:"
+
e
.
screenY
)
;
}
)
;
|
理解鼠标滚轮事件:
IE6首先实现了mousewheel事件,此后opera,chrome和safari也都实现了这个事件,当用户通过鼠标滚轮与页面交互,在垂直方向上滚动页面时(无论向上还是向下),就会触发mousewheel事件,这个事件可以在任何元素上触发,最终会冒泡到document(IE8)或window(IE9,Opera,Chrome,Safari)对象,与mousewheel事件对应的event对象外,还有一个属性wheelDelta属性,当用户向前滚动鼠标滚轮时,wheelDelta是120的倍数,当用户向后滚动鼠标滚轮时,wheelDelta是-120的倍数。
将mousewheel事件给页面任何元素或document对象,即可处理鼠标滚轮操作;如下代码:
1
2
3
4
|
EventUtil
.
addHandler
(
btn
,
'mousewheel'
,
function
(
e
)
{
e
=
EventUtil
.
getEvent
(
e
)
;
alert
(
e
.
wheelDelta
)
;
}
)
;
|
如上代码,我不是在document对象或者window对象上,而是在页面btn元素上触发的;但是我们要注意,在Opera9.5之前的版本中,wheelDelta值的正负号是颠倒的,如果我们要支持Opera9.5版本之前的话,那么我们需要浏览器检测技术来检测下;如下代码
1
2
3
4
5
6
|
EventUtil
.
addHandler
(
document
,
"mousewheel"
,
function
(
event
)
{
event
=
EventUtil
.
getEvent
(
event
)
;
// var delta = (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta);
var
delta
=
event
.
wheelDelta
;
alert
(
delta
)
;
}
)
;
|
但是client.engine.opera 这句代码运行下会报错,因为目前还没有封装这个方法,所以等下一个博客我会研究代理检测封装下这个方法;所以先不考虑opera9.5,先注释掉这句代码;
但是FireFox支持一个为DOMMouseScroll的事件,也是在鼠标滚轮滚动时触发,与mousewheel事件一样,但是他的有关鼠标滚轮信息保存在detail属性中,当鼠标向前滚动时,这个属性值是-3的倍数,当鼠标滚轮向后滚动时,这个属性值是3的倍数;也可以给DOMMouseScroll事件使用在任何元素上,且这个事件会冒泡到window对象上,因此我们可以这样添加滚轮信息的代码如下:
1
2
3
4
|
EventUtil
.
addHandler
(
document
,
"DOMMouseScroll"
,
function
(
event
)
{
event
=
EventUtil
.
getEvent
(
event
)
;
alert
(
event
.
detail
)
;
}
)
;
|
我们现在可以给跨浏览器下的滚轮事件;代码如下:
1
2
3
4
5
6
7
8
|
function
getWheelDelta
(
event
)
{
if
(
event
.
wheelDelta
)
{
// return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta);
return
event
.
wheelDelta
;
}
else
{
return
-
event
.
detail
*
40
}
}
|
getWheelDelta方法首先检测了事件对象是否包含了wheelDelta属性,如果包含则返回属性值,如果不包含,那么我们就当作是firefox浏览器,那么假设相应的值保存在detail属性中,有了上面的方法后,我们现在可以将相同的事件指定给mousewheel事件和DOMMouseScroll事件了;
1
2
3
4
5
6
7
|
EventUtil
.
addHandler
(
document
,
"DOMMouseScroll"
,
handleMouseWheel
)
;
EventUtil
.
addHandler
(
document
,
"mousewheel"
,
handleMouseWheel
)
;
function
handleMouseWheel
(
event
)
{
event
=
EventUtil
.
getEvent
(
event
)
;
var
delta
=
EventUtil
.
getWheelDelta
(
event
)
;
alert
(
delta
)
;
}
|
滚轮向上滚动是正数120,向下滚动是负数-120,所以根据是否大于0,可以判断是向下滚动还是向上滚动;
理解字符编码charCode
IE9+,firefox,chrome和safari的event对象都支持一个charCode属性,这个属性只有在发生keypress事件时才包含值,而且这个值是按下的那个键所代表字符的ASCLL编码,但是IE8及之前或者opera不支持这个属性,但是我们可以使用keyCode这个属性代替.在取得了字符编码之后,就可以使用String.fromCharCode()将其转换成实际的字符。
如下代码:
1
2
3
4
5
6
7
|
getCharCode
:
function
(
event
)
{
if
(
typeof
event
.
charCode
==
'number'
)
{
return
event
.
charCode
;
}
else
{
return
event
.
keyCode
;
}
}
|
我们现在可以给EventUtil添加事件了,如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
var
EventUtil
=
{
addHandler
:
function
(
element
,
type
,
handler
)
{
if
(
element
.
addEventListener
)
{
element
.
addEventListener
(
type
,
handler
,
false
)
;
}
else
if
(
element
.
attachEvent
)
{
element
.
attachEvent
(
"on"
+
type
,
handler
)
;
}
else
{
element
[
"on"
+
type
]
=
handler
;
}
}
,
removeHandler
:
function
(
element
,
type
,
handler
)
{
if
(
element
.
removeEventListener
)
{
element
.
removeEventListener
(
type
,
handler
,
false
)
;
}
else
if
(
element
.
detachEvent
)
{
element
.
detachEvent
(
"on"
+
type
,
handler
)
;
}
else
{
element
[
"on"
+
type
]
=
null
;
}
}
,
getEvent
:
function
(
event
)
{
return
event
?
event
:
window
.
event
;
}
,
getTarget
:
function
(
event
)
{
return
event
.
target
||
event
.
srcElement
;
}
,
preventDefault
:
function
(
event
)
{
if
(
event
.
preventDefault
)
{
event
.
preventDefault
(
)
;
}
else
{
event
.
returnValue
=
false
;
}
}
,
stopPropagation
:
function
(
event
)
{
if
(
event
.
stopPropagation
)
{
event
.
stopPropagation
(
)
;
}
else
{
event
.
cancelBubble
=
true
;
}
}
,
getRelatedTarget
:
function
(
event
)
{
if
(
event
.
relatedTarget
)
{
return
event
.
relatedTarget
;
}
else
if
(
event
.
toElement
)
{
return
event
.
toElement
;
}
else
if
(
event
.
fromElement
)
{
return
event
.
fromElement
;
}
else
{
return
null
;
}
}
,
getWheelDelta
:
function
(
event
)
{
if
(
event
.
wheelDelta
)
{
return
event
.
wheelDelta
;
}
else
{
return
-
event
.
detail
*
40
}
}
,
getCharCode
:
function
(
event
)
{
if
(
typeof
event
.
charCode
==
'number'
)
{
return
event
.
charCode
;
}
else
{
return
event
.
keyCode
;
}
}
}
;
|
我们现在可以做一个demo如下:
1
2
3
4
5
6
7
8
|
如下代码:
var
inputDiv
=
document
.
getElementById
(
"inputDiv"
)
;
EventUtil
.
addHandler
(
inputDiv
,
'keypress'
,
function
(
event
)
{
event
=
EventUtil
.
getEvent
(
event
)
;
var
code
=
EventUtil
.
getCharCode
(
event
)
;
alert
(
EventUtil
.
getCharCode
(
event
)
)
;
// 弹出字符编码
alert
(
String
.
fromCharCode
(
code
)
)
;
// 弹出字符
}
)
;
|
HTML5事件
1. contextmenu事件
contextmenu事件在windows操作系统下,我们是使用右键就可以自定义右键弹出菜单,但是我们使用右键的时候会有默认的菜单,因此我们需要使用阻止默认事件这个方法来阻止掉;此事件也是属于鼠标事件,因此此事件包含与光标位置中所有的属性,比如我们右键如下图所示:
1
2
3
4
5
6
7
8
9
|
HTML代码如下:
<
div
id
=
"myDiv"
>
Right
click
or
Ctrl
+
click
me
to
get
a
custom
context
menu
.
Click
anywhere
else
to
get
the
default
context
menu
.
<
/
div
>
<
ul
id
=
"myMenu"
style
=
"position:absolute;visibility:hidden;background-color:
silver"
>
<
li
>
<
a
href
=
"http://www.nczonline.net"
>
Nicholas’
site
<
/
a
>
<
/
li
>
<
li
>
<
a
href
=
"http://www.wrox.com"
>
Wrox
site
<
/
a
>
<
/
li
>
<
li
>
<
a
href
=
"http://www.yahoo.com"
>
Yahoo
!
<
/
a
>
<
/
li
>
<
/
ul
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
JS代码如下:
var
div
=
document
.
getElementById
(
"myDiv"
)
;
EventUtil
.
addHandler
(
div
,
"contextmenu"
,
function
(
event
)
{
event
=
EventUtil
.
getEvent
(
event
)
;
EventUtil
.
preventDefault
(
event
)
;
var
menu
=
document
.
getElementById
(
"myMenu"
)
;
menu
.
style
.
left
=
event
.
clientX
+
"px"
;
menu
.
style
.
top
=
event
.
clientY
+
"px"
;
menu
.
style
.
visibility
=
"visible"
;
}
)
;
EventUtil
.
addHandler
(
document
,
"click"
,
function
(
event
)
{
document
.
getElementById
(
"myMenu"
)
.
style
.
visibility
=
"hidden"
;
}
)
;
|
如上,我们是通过右键的clientX和clientY来确定菜单的位置;当我点击文档document的时候 就隐藏该菜单;
浏览器支持有:IE,Firefox,Safari,chrome和Opera11+
beforeunload事件
此事件是给页面在卸载之前,给用户一个提示,是否需要卸载页面提示给用户,为了显示这个对话框,对IE和firefox而言,必须将event.returnValue的值设置为要显示给用户的字符串;但是对于safari和chrome而言,可以返回此字符串即可;
如下代码:
1
2
3
4
5
6
|
EventUtil
.
addHandler
(
window
,
"beforeunload"
,
function
(
event
)
{
event
=
EventUtil
.
getEvent
(
event
)
;
var
message
=
"I'm really going to miss you if you go."
;
event
.
returnValue
=
message
;
return
message
;
}
)
;
|
当用户关闭游览器的时候,会弹出如下窗口给用户提示,如下:
点击离开此页按钮 即关闭窗口,点击留在此页按钮 即留在当前页面,但是当我按F5刷新页面的时候,同样会弹出窗口提示,如下:
浏览器支持:IE,firefox,chrome和safari都支持,但是Opera11及之前的版本不支持;
理解hashchange事件
HTML5中新增加了hashchange事件,以便在URL的参数列表(url中的#号后面的所有参数发生改变时通知开发人员),在Ajax应用中,开发人员经常使用url参数列表保存状态或导航信息;
我们必须把hashchange事件添加到window对象中,然后当url参数列表只要发生变化就会调用此事件,此事件对象event包含2个属性,oldURL和newURL,这两个属性分别保存着URL变化前后的完整URL;
支持的浏览器有:IE8+,firefox3.6+,safari5+,chrome和opera10.6+
在这些浏览器中,只有firefox3.6+,chrome和opera支持oldURL和newURL属性;
如下代码:
1
2
3
|
EventUtil
.
addHandler
(
window
,
"hashchange"
,
function
(
event
)
{
alert
(
"Old URL: "
+
event
.
oldURL
+
"\nNew URL: "
+
event
.
newURL
)
;
}
)
;
|
当我第一次#号参数后面是aa,现在改成aaaa,就会触发此事件,如下所示:
有些浏览器并不支持oldURL和newURL,因此我们可以使用location.hash来保存当前的参数列表,如下代码:
1
2
3
4
5
|
EventUtil
.
addHandler
(
window
,
"hashchange"
,
function
(
event
)
{
alert
(
location
.
hash
)
;
}
)
;
|
当#号后面我改成bbb参数时候,会弹出如下所示:
可以使用如下代码来检测浏览器是否支持hashchange事件;
1
2
|
var
isSupported
=
(
"onhashchange"
in
window
)
;
alert
(
isSupported
)
;
|
如果IE8 是在IE7 文档模式下运行,即使功能无效它也会返回true。为解决这个问题,可以使用
以下这个更稳妥的检测方式:
1
|
var
isSupported
=
(
"onhashchange"
in
window
)
&&
(
document
.
documentMode
===
undefined
||
document
.
documentMode
>
7
)
;
|
设备事件中的—orientationchange事件
苹果公司为移动safari添加的orientationchange事件是能让用户确定何时将设备由横向查看模式切换到纵向模式触发的事件;此属性中包含三个值,0表示肖像模式;90表示向左旋转的横向模式(主屏幕按钮在右侧),-90表示向右旋转的横向模式(主屏幕按钮在左侧),如下图所示:
只要用户改变了设备的查看模式,就会触发orientationchange事件,
使用IOS设备即可演示效果:代码如下:
1
2
3
4
5
6
7
|
EventUtil
.
addHandler
(
window
,
"load"
,
function
(
event
)
{
var
div
=
document
.
getElementById
(
"myDiv"
)
;
div
.
innerHTML
=
"Current orientation is "
+
window
.
orientation
;
EventUtil
.
addHandler
(
window
,
"orientationchange"
,
function
(
event
)
{
div
.
innerHTML
=
"Current orientation is "
+
window
.
orientation
;
}
)
;
}
)
;
|
理解移动端的事件—触摸与手势事件
有以下几个触摸事件:
- touchstart: 当手指触摸屏幕时触发,即使是一个手指放在屏幕上也会触发。
- touchmove:当手指在屏幕上滑动时连续地触发,这个事件发生期间,我们可以使用preventDefault()事件可以阻止滚动。
- touchend: 当手指从屏幕上移开时触发。
- touchcancel: 当系统停止跟踪触摸时触发。
上面几个事件都属于冒泡事件,我们可以对此进行取消事件,每个触摸的event对象都提供了在鼠标中常见的属性;
bubbles, cancelable,view,clientX, clientY ,screenX, screenY,detail, altKey, shiftKey, ctrlKey, metaKey,
除了常见的DoM属性外,触摸事件还包含下列三个用于跟踪触摸的属性;
touches: 表示当前跟踪的触摸操作的Touch对象数组;
targetTouches: 特定与事件目标的Touch对象数组;
changeTouches: 表示自上次触摸以来发生了什么改变的Touch对象数组;
原文地址:http://web.jobbole.com/82419/
http://web.jobbole.com/83168/