JQuery基础教程:事件(下)

 事件传播

    为了说明不可单击的页面元素处理单击事件的能力,例如样式转换器中包含按钮的div元素或者兄弟元素h3,我们来实现一个鼠标指针进入元素和离开元素时的效果,首先需要添加一种翻转状态,表明能与鼠标进行某种交互,然后我们.hover()方法给h3元素添加这个样式,伪代码如下:

<style>
.hover {
cursor: pointer;
background-color: #afa;
}
</style
<script>
$(document).ready(function() {
$('#switcher h3').hover(function() {
$(this).addClass('hover');
}, function() {
$(this).removeClass('hover');
});
});
</sctipt> <body>
...
</body>

代码

JQuery基础教程:事件(下)

注:.hover()方法接受两个函数参数。第一个函数会在鼠标指针进入被选择的元素时执行,而第二个函数会在鼠标指针离开该元素时触发

  • 事件的旅程

当页面上发生一个事件时,每个层次上的DOM元素都有机会处理这个事件。以下面的页面模型为例:

 <div class="foo">
<span class="bar">
<a href="http://www.example.com/">
The quick brown fox jumps over the lazy dog.
</a>
</span>
<p>
How razorback-jumping frogs can level six piqued gymnasts!
</p>
</div>

JQuery基础教程:事件(下)JQuery基础教程:事件(下)允许多个元素响应单击事件的一种策略叫做事件捕获。在事件捕获的过程中,事件首先会交给最外层的元素,接着再交给更具体的元素。在这个例子中,意味着单击事件首先会传递给<div>,然后是<span>,最后是<a>。另一种相反的策略叫做事件冒泡。即当事件发生时,会首先发送给最具体的元素,在这个元素获得响应机会之后,事件会向上冒泡到更一般的元素。在我们的例子中,<a>会首先处理事件,然后按照顺序依次是<span>和<div>

  • 事件冒泡的副作用

假设在我们的例子中,为<div>添加了一个mouseout事件处理程序。当用户的鼠标指针退出这个<div>时,会按照预期运行mouseout处理程序。因为这个过程发生在顶层元素上,所以其他元素不会取得这个事件。但是,当指针从<a>元素上离开时,<a>元素也会取得一个mouseout事件。然后,这个事件会向上冒泡到<span>和<div>,从而触发上述的事件处理程序。这种冒泡序列很可能不是我们所希望的

 通过事件对象改变事件的旅程

假设我们希望增大触发样式转换器折叠或扩展的可单击区域。一种方案就是将事件处理程序从标签移至包含它的<div>元素

$(document).ready(function() {
$('#switcher').click(function() {
$('#switcher button').toggleClass('hidden');
});
});

JS

完整代码如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<style type="text/css">
body.large {
font-size: 1.5em;
} body.narrow {
width: 250px;
} .selected {
font-weight: bold;
} .hover {
cursor: pointer;
background-color: #afa;
} .hidden {
display:none;
} </style>
<script src="Scripts/jquery-1.8.2.js"></script>
<script src="Scripts/jquery-1.8.2.min.js"></script>
<script> $(document).ready(function () {
$('#switcher-default').addClass('selected');
$('#switcher button').on('click', function () {
var bodyClass = this.id.split('-')[1];
var bodyClass = this.id.split('-')[1];
$('body').removeClass().addClass(bodyClass);
$('#switcher button').removeClass('selected');
$(this).addClass('selected');
//eventobj.stopPropagation(); //阻止事件冒泡
//return false; //也可以阻止事件冒泡,也可以阻止默认事件
});
}); $(document).ready(function () {
$('#switcher h3').hover(function () {
$(this).addClass('hover');
}, function () {
$(this).removeClass('hover');
});
}); $(document).ready(function () {
$('#switcher').click(function () {
$('#switcher button').toggleClass('hidden');
});
}); </script>
</head>
<body>
<div id="switcher" class="switcher">
<h3>样式转换器</h3>
<button id="switcher-default">
默认视图
</button>
<button id="switcher-narrow">
窄列视图
</button>
<button id="switcher-large">
大字视图
</button>
</div>
<h2>Shakespeare's Plays</h2> <table>
<tr>
<td>As You Like It</td>
<td>Comedy</td>
<td></td>
</tr>
<tr>
<td>All's Well that Ends Well</td>
<td>Comedy</td>
<td>1601</td>
</tr>
<tr>
<td>Hamlet</td>
<td>Tragedy</td>
<td>1604</td>
</tr>
<tr>
<td>Macbeth</td>
<td>Tragedy</td>
<td>1606</td>
</tr>
<tr>
<td>Romeo and Juliet</td>
<td>Tragedy</td>
<td>1595</td>
</tr>
<tr>
<td>Henry IV, Part I</td>
<td>History</td>
<td>1596</td>
</tr>
<tr>
<td>Henry V</td>
<td>History</td>
<td>1599</td>
</tr>
</table>
<h2>Shakespeare's Sonnets</h2>
<table>
<tr>
<td>The Fair Youth</td>
<td>1–126</td>
</tr>
<tr>
<td>The Dark Lady</td>
<td>127–152</td>
</tr>
<tr>
<td>The Rival Poet</td>
<td>78–86</td>
</tr>
</table>
</body>
</html>

完整代码

JQuery基础教程:事件(下)  这种改变会使样式转换器的整个区域都可以通过单击切换其可见性。但时也造成了一个问题,即单击按钮会在修改内容区的样式之后折叠样式转换器。导致这个问题的原因就是事件冒泡,即事件首先被按钮处理,然后又沿着DOM树向上传递,直至到达<div id="switcher">激活事件处理程序并隐藏按钮。要解决这个问题,必须访问事件对象

JQuery基础教程:事件(下)

        注:事件对象是一种DOM结构,它会在元素获得处理事件的机会时传递给被调用的事件处理程序。这个对象中包含着与事件有关的信息(例如事件发生时的鼠标指针位置),也提供了可以用来影响事件在DOM中传递进程的一些方法

  • 事件目标

变量event保存着事件对象。而event.target属性保存着发生事件的目标元素。通过.target,可以确定DOM中首先接收到事件的元素(即实际被单击的元素)。而且,我们知道this引用的是处理事件的DOM元素,修改上面的代码可以得到如下代码

$(document).ready(function() {
$('#switcher').click(function(event) {
if (event.target == this) {
$('#switcher button').toggleClass('hidden');
}
});
});

代码

JQuery基础教程:事件(下)

此时的代码确保了被单击的元素是<div id="switcher">,而不是其他后代元素。现在,单击按钮不会再折叠样式转换器,而单击转换器背景区则会触发折叠操作。但是,单击标签(<h3>)同样什么也不会发生,因为它也是一个后代元素

  • 停止事件传播

删除刚才的event.target==this,我们来给按钮的事件处理添加一个事件对象并调用event.stopPropagation()方法,这样可以阻止按钮的事件冒泡行为,这样一来,单击按钮的事件会被按钮处理,而且只会被按钮处理。单击样式转换器的其他地方则可以折叠和扩展整个区域,代码如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<style type="text/css">
body.large {
font-size: 1.5em;
} body.narrow {
width: 250px;
} .selected {
font-weight: bold;
} .hover {
cursor: pointer;
background-color: #afa;
} .hidden {
display:none;
} </style>
<script src="Scripts/jquery-1.8.2.js"></script>
<script src="Scripts/jquery-1.8.2.min.js"></script>
<script> $(document).ready(function () {
$('#switcher-default').addClass('selected');
$('#switcher button').on('click', function (event) {
var bodyClass = this.id.split('-')[1];
var bodyClass = this.id.split('-')[1];
$('body').removeClass().addClass(bodyClass);
$('#switcher button').removeClass('selected');
$(this).addClass('selected');
event.stopPropagation(); //阻止事件冒泡
//return false; //也可以阻止事件冒泡,也可以阻止默认事件
});
}); $(document).ready(function () {
$('#switcher h3').hover(function () {
$(this).addClass('hover');
}, function () {
$(this).removeClass('hover');
});
}); $(document).ready(function () {
$('#switcher').click(function (event) {
$('#switcher button').toggleClass('hidden');
});
}); </script>
</head>
<body>
<div id="switcher" class="switcher">
<h3>样式转换器</h3>
<button id="switcher-default">
默认视图
</button>
<button id="switcher-narrow">
窄列视图
</button>
<button id="switcher-large">
大字视图
</button>
</div>
<h2>Shakespeare's Plays</h2> <table>
<tr>
<td>As You Like It</td>
<td>Comedy</td>
<td></td>
</tr>
<tr>
<td>All's Well that Ends Well</td>
<td>Comedy</td>
<td>1601</td>
</tr>
<tr>
<td>Hamlet</td>
<td>Tragedy</td>
<td>1604</td>
</tr>
<tr>
<td>Macbeth</td>
<td>Tragedy</td>
<td>1606</td>
</tr>
<tr>
<td>Romeo and Juliet</td>
<td>Tragedy</td>
<td>1595</td>
</tr>
<tr>
<td>Henry IV, Part I</td>
<td>History</td>
<td>1596</td>
</tr>
<tr>
<td>Henry V</td>
<td>History</td>
<td>1599</td>
</tr>
</table>
<h2>Shakespeare's Sonnets</h2>
<table>
<tr>
<td>The Fair Youth</td>
<td>1–126</td>
</tr>
<tr>
<td>The Dark Lady</td>
<td>127–152</td>
</tr>
<tr>
<td>The Rival Poet</td>
<td>78–86</td>
</tr>
</table>
</body>
</html>

代码

  • 阻止事件默认行为

对于一个锚元素(<a>),当用户单击时浏览器会加载一个新页面,这种行为与事件处理程序不是同一个概念,它是单击锚元素的默认操作。即便在事件对象上调用.stopPropagation()方法也不能禁止这种默认操作,因为默认操作不是在正常的事件传播流中发生的。在这种情况下,.preventDefault()方法则可以阻止事件的默认行为。另外,如果想要同时停止事件传播和默认操作,可以在事件处理程序中返回false,代码如下:

 $(document).ready(function () {
$('#switcher-default').addClass('selected');
$('#switcher button').on('click', function (event) {
var bodyClass = this.id.split('-')[1];
var bodyClass = this.id.split('-')[1];
$('body').removeClass().addClass(bodyClass);
$('#switcher button').removeClass('selected');
$(this).addClass('selected');
//event.stopPropagation(); //阻止事件冒泡
//event.preventDefault(); //阻止默认事件和事件冒泡
return false; //也可以阻止事件冒泡,也可以阻止默认事件
});
});

代码

 事件委托

事件冒泡也有好处,通过事件冒泡我们可以用很少的代码为元素注册重复的事件,例如,一个table里有很多td,如果为每个td都注册一个hover事件,不仅需要遍历table的子节点,而且严重降低了性能,通过事件委托可以这样写

$("table").delegate("td", "hover", function(){
$(this).toggleClass("hover"); });
  将每个单元格的hover事件委托给了table元素,每当单元格td触发hover事件是就会执行元素table绑定的函数fn
上一篇:fixtures 的语法


下一篇:Pytest系列(10) - fixture 传参数 request的详细使用