8.5.5 标签页事件

Bootstrap为导航标签提供了如下事件。

事件 描述
show.bs.tab 当指定标签开始显示时触发该事件。
shown.bs.tab 当指定标签完全显示出来时触发该事件。
hide.bs.tab 当指定标签开始隐藏时触发该事件。
hidden.bs.tab 当指定标签完全隐藏时触发该事件。

javascript事件属性

target事件属性

target事件属性可返回事件的目标节点,也就是触发该事件的节点.

relatedTarget事件属性

relatedTarget事件属性返回与事件的目标节点相关的节点。

  • 对于mouseover事件来说,该属性是鼠标指针移到目标节点上时所离开的那个节点。
  • 对于mouseout事件来说,该属性是离开目标时,鼠标指针进入的节点。
  • 对于其他类型的事件来说,这个属性没有用。

当某个导航标签上的事件监听函数被触发时,程序可通过事件的target属性获取该事件当前的事件源,比如单击某个导航标签,该导航标签即显示出来,那么该事件的target属性就返回当前被单击的导航标签。
此外,事件的relatedTarget 属性则获取当前事件所关联的事件源,比如单击某个导航标签,该操作将会导致另一个之前显示的标签被隐藏起来,那么该事件的relatedTarget属性就返回即将被隐藏的导航标签。

程序示例

下面代码示范了标签页的事件的用法。

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title> 标签页事件 </title>
<link rel="stylesheet" href="../bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="../bootstrap/css/bootstrap-theme.min.css">
<script type="text/javascript" src="../jquery-3.1.1.js"></script>
<script type="text/javascript" src="../bootstrap/js/bootstrap.min.js"></script>
</head>

<body>
<div class="container">
<!-- 导航 -->
<ul class="nav nav-tabs">
<!-- 默认激活, -->
<li class="active">
<!-- data-toggle="tab"表示该标签可触发标签页 -->
<a href="#java" data-toggle="tab">疯狂Java讲义</a>
</li>
<li>
<!-- data-toggle="tab"表示该标签可触发标签页 -->
<a href="#android" data-toggle="tab">疯狂Android讲义</a>
</li>
<!-- 下拉菜单 -->
<li class="dropdown">
<!-- data-toggle="dropdown"表示该该链接可以触发下拉菜单 -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">前端图书
<span class="caret"></span>
</a>
<!-- 菜单内容 -->
<ul class="dropdown-menu">
<li><a href="#html" data-toggle="tab">疯狂HTML 5讲义</a></li>
<li role="separator" class="divider"></li>
<li><a href="#front" data-toggle="tab">疯狂前端开发讲义</a></li>
</ul>
</li>
</ul>
<!-- 标签页内容 -->
<div class="tab-content">
<!-- 标签页 -->
<div class="tab-pane active" id="java">
<h3>疯狂Java讲义</h3>
<p>必读的Java学习经典,你懂的,不多说。</p>
</div>
<div class="tab-pane" id="android">
<h3>疯狂Android讲义</h3>
<p>最全面、最详细的Android学习图书,全面覆盖Android开发手册</p>
</div>
<div class="tab-pane" id="html">
<h3>疯狂HTML 5讲义</h3>
<p>全面、细致的前端开发基础图书,全面深入介绍HTML 5/CSS 3/JavaScript知识。</p>
</div>
<div class="tab-pane" id="front">
<h3>疯狂前端开发讲义</h3>
<p>前端开发的进阶图书,全面深入介绍jQuery/AngularJS/Bootstrap等框架。</p>
</div>
</div>
</div>
<script type="text/javascript">
// 导航上的按钮事件
$(".nav-tabs a").first().on('show.bs.tab', function (e) {
console.log('触发show事件的元素:' + e.target.getAttribute("href") + ",离开的元素:" + e.relatedTarget.getAttribute(
"href"));
}).on('shown.bs.tab', function (e) {
console.log('触发shown事件的元素:' + e.target.getAttribute("href") + ",离开的元素:" + e.relatedTarget.getAttribute(
"href"));
}).on('hide.bs.tab', function (e) {
console.log('触发hide事件的元素:' + e.target.getAttribute("href") + ",进入的元素:" + e.relatedTarget.getAttribute(
"href"));
}).on('hidden.bs.tab', function (e) {
console.log('触发hidden事件的元素:' + e.target.getAttribute("href") + ",进入的元素:" + e.relatedTarget.getAttribute(
"href"));
})
</script>
</body>

</html>

在该示例中,为标签页中第一个标签的4个事件都绑定了事件处理函数,这样无论第一个标签上发生哪种事件,这些事件处理函数都会被触发。
浏览该页面时,系统默认显示第一个标签。

  • 单击第二个标签(#android标签),标签页将会隐藏第一个标签,因此将会依次触发第一个标签hide.bs.tabhidden.bs.tab 两个事件;
    • 此时可以通过该事件对象的relatedTarget属性获取要显示的标签(第二个标签)
  • 再次单击第一个标签(#java标签),标签页显示第一个标签,因此将会依次触发第一个标签show.bs.tabshown.bs.tab两个事件。
    • 此时可以通过该事件对象的relatedTarget属性获取要隐藏的标签(第二个标签)

控制台输出如下:

1
2
3
4
触发hide事件的元素:#java,进入的元素:#android tab-content-event.html:72:12
触发hidden事件的元素:#java,进入的元素:#android tab-content-event.html:75:12
触发show事件的元素:#java,离开的元素:#android tab-content-event.html:66:12
触发shown事件的元素:#java,离开的元素:#android tab-content-event.html:69:12

8.5.4 胶囊式标签页

如果要实现胶囊式标签页,只要对普通标签页进行如下修改即可:

  1. 将导航组件的导航风格从.nav-tabs改为.nav-pills,这意味着导航组件改为使用胶囊式导航。
  2. 将导航标签的data-toggle="tab"改为data-toggle="pill",这意味着导航链接以胶囊式风格切换内容标签。

程序示例

如下代码示范了胶囊式标签页的实现方法。

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
66
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title> 胶囊式标签页 </title>
<link rel="stylesheet" href="../bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="../bootstrap/css/bootstrap-theme.min.css">
</head>

<body>
<div class="container">
<!-- 胶囊式导航 -->
<!-- 1号代码 -->
<ul class="nav nav-pills">
<li class="active">
<!-- 2号代码:data-toggle="pill"表示该链接会以胶囊式打开标签页 -->
<!-- href="#java"指定触发的是ID为java的标签页 -->
<a href="#java" data-toggle="pill">
疯狂Java讲义</a>
</li>
<li><a href="#android" data-toggle="pill">疯狂Android讲义</a></li>
<!-- 下拉菜单 -->
<li class="dropdown">
<!-- 下拉菜单按钮 -->
<!-- data-toggle="dropdown"表示该链接可以切换下拉菜单的状态 -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">前端图书
<span class="caret"></span>
</a>
<!-- 菜单内容 -->
<ul class="dropdown-menu">
<li><a href="#html" data-toggle="pill">疯狂HTML 5讲义</a></li>
<li role="separator" class="divider"></li>
<li><a href="#front" data-toggle="pill">疯狂前端开发讲义</a></li>
</ul>
</li>
</ul>
<!-- 标签页内容面板 -->
<div class="tab-content">
<!-- 标签页,fade表示动画切换,active表示默认打开该标签页 -->
<div class="tab-pane fade active" id="java">
<h3>疯狂Java讲义</h3>
<p>必读的Java学习经典,你懂的,不多说。</p>
</div>
<!-- 标签页 -->
<div class="tab-pane fade" id="android">
<h3>疯狂Android讲义</h3>
<p>最全面、最详细的Android学习图书,全面覆盖Android开发手册</p>
</div>
<div class="tab-pane fade" id="html">
<h3>疯狂HTML 5讲义</h3>
<p>全面、细致的前端开发基础图书,全面深入介绍HTML 5/CSS 3/JavaScript知识。</p>
</div>
<div class="tab-pane fade" id="front">
<h3>疯狂前端开发讲义</h3>
<p>前端开发的进阶图书,全面深入介绍jQuery/AngularJS/Bootstrap等框架。</p>
</div>
</div>
</div>
<script type="text/javascript" src="../jquery-3.1.1.js"></script>
<script type="text/javascript" src="../bootstrap/js/bootstrap.min.js"></script>
</body>

</html>

在该示例中的

  • 1号代码将导航组件的导航风格改为了.nav-pills,这意味着该导航组件将会变成胶囊式风格导航。
  • 2号代码则修改了导航链接的data-toggle属性,将该属性的值改为了pill,指定为胶囊式标签页。

胶囊式风格的导航和标签式风格的导航的区别

  • 胶囊式风格的导航带呈现反色效果,也就是导航的背景有颜色,文字时白色.
  • 标签式导航背景是白色,文字带颜色.

8.5.3 使用JS切换标签页

使用JS切换标签页也非常简单。tab.js插件为导航链接提供了tab()方法,只要调用该方法时传入"show"字符串参数即可显示对应的内容标签。
此外,如果希望切换标签页时使用过渡动画,只要为每个内容标签都指定.fade样式即可。

程序示例

如下代码示范了如何使用JS切换标签页。

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
66
67
68
69
70
71
72
73
74
75
76
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title> 切换标签页 </title>
<link rel="stylesheet" href="../bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="../bootstrap/css/bootstrap-theme.min.css">
<script type="text/javascript" src="../jquery-3.1.1.js"></script>
<script type="text/javascript" src="../bootstrap/js/bootstrap.min.js"></script>
</head>

<body>
<div class="container">
<!-- 导航条 -->
<ul class="nav nav-tabs" id="tabNav">

<li class="active">
<!-- href="#java"指明要触发ID为java的标签页 -->
<a href="#java">疯狂Java讲义</a>
</li>
<li>
<!-- 通过href="#android"指定要触发的标签页 -->
<a href="#android">疯狂Android讲义</a>
</li>
<!-- 下拉菜单 -->
<li class="dropdown">
<!-- 下拉菜单触发按钮 -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">前端图书
<span class="caret"></span>
</a>
<!-- 下拉菜单内容 -->
<ul class="dropdown-menu">
<!-- 通过href="#android"指定要触发的标签页 -->
<li><a href="#html">疯狂HTML 5讲义</a></li>
<!-- 分割条 -->
<li role="separator" class="divider"></li>
<!-- 通过href="#android"指定要触发的标签页 -->
<li><a href="#front">疯狂前端开发讲义</a></li>
</ul>
</li>
</ul>
<!-- 标签页内容面板 -->
<div class="tab-content">
<!-- 标签页 fade:动画效果-->
<div class="tab-pane fade active" id="java">
<h3>疯狂Java讲义</h3>
<p>必读的Java学习经典,你懂的,不多说。</p>
</div>
<div class="tab-pane fade" id="android">
<h3>疯狂Android讲义</h3>
<p>最全面、最详细的Android学习图书,全面覆盖Android开发手册</p>
</div>
<div class="tab-pane fade" id="html">
<h3>疯狂HTML 5讲义</h3>
<p>全面、细致的前端开发基础图书,全面深入介绍HTML 5/CSS 3/JavaScript知识。</p>
</div>
<div class="tab-pane fade" id="front">
<h3>疯狂前端开发讲义</h3>
<p>前端开发的进阶图书,全面深入介绍jQuery/AngularJS/Bootstrap等框架。</p>
</div>
</div>
</div>
<script type="text/javascript">
// 处理导航条上的链接标签的点击事件
$("#tabNav a").click(function () {
// 调用该标签的tab方法
// 1号代码
$(this).tab("show");
});
</script>
</body>

</html>

在该代码示例中,删除了导航链接中所有的data-*属性,但修改了链接的href属性(href属性可代替data-target属性),每个href属性值都是一个ID选择器,这样Bootstrap即可知道该导航链接要打开哪个内容标签。
1号代码调用了导航链接的tab()方法以显示该导航链接对应的内容标签,这样该标签页组件即可实现正常切换。

8.5.2 使用data-*属性切换标签页

标签页的两种切换方式

与前面介绍的JS组件类似的是,Bootstrap的标签页同样支持两种切换方式。

  1. 使用data-*属性实现切换。
  2. 使用JS脚本实现切换。

如何使用data-*属性切换标签页

为了使用data-*属性实现切换,只要为导航组件导航链接指定如下两个属性即可。

  1. data-toggle:可将该属性指定为”tab"或”pill"字符串,其中前者表示普通标签页,后者表示胶囊式标签页。
  2. data-target:该属性指定该导航链接对应的标签页。该属性可以是各种CSS选择器,通常建议使用ID 选择器。对于使用超链接作为导航链接的情形,可使用超链接的href属性代替该属性。

程序示例

如下代码示范了如何使用data-*属性实现标签页的切换。

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
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title> 切换标签页 </title>
<link rel="stylesheet" href="../bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="../bootstrap/css/bootstrap-theme.min.css">
</head>

<body>
<div class="container">
<!-- 导航组件 -->
<ul class="nav nav-tabs">
<!-- data-toggle="tab"表示该点击可以触发标签页 -->
<!-- data-target="#java"指明要触发哪个标签页:触发id为java的标签页 -->
<li class="active"><a href="#" data-toggle="tab" data-target="#java">
疯狂Java讲义</a></li>
<li><a href="#" data-toggle="tab" data-target="#android">疯狂Android讲义</a></li>
<!-- 下拉菜单组件 -->
<li class="dropdown">
<!-- data-toggle="dropdown"表示该链接可以触发下拉菜单 -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">前端图书
<span class="caret"></span>
</a>
<!-- 菜单 -->
<ul class="dropdown-menu">
<!-- data-toggle="tab"表示该链接可以触发标签页 -->
<li><a href="#" data-toggle="tab" data-target="#html">疯狂HTML 5讲义</a></li>
<li role="separator" class="divider"></li>
<li><a href="#" data-toggle="tab" data-target="#front">疯狂前端开发讲义</a></li>
</ul>
</li>
</ul>
<!-- 标签页内容面板 -->
<div class="tab-content">
<!-- 标签页 -->
<div class="tab-pane active" id="java">
<h3>疯狂Java讲义</h3>
<p>必读的Java学习经典,你懂的,不多说。</p>
</div>
<div class="tab-pane" id="android">
<h3>疯狂Android讲义</h3>
<p>最全面、最详细的Android学习图书,全面覆盖Android开发手册</p>
</div>
<div class="tab-pane" id="html">
<h3>疯狂HTML 5讲义</h3>
<p>全面、细致的前端开发基础图书,全面深入介绍HTML 5/CSS 3/JavaScript知识。</p>
</div>
<div class="tab-pane" id="front">
<h3>疯狂前端开发讲义</h3>
<p>前端开发的进阶图书,全面深入介绍jQuery/AngularJS/Bootstrap等框架。</p>
</div>
</div>
</div>
<script type="text/javascript" src="../jquery-3.1.1.js"></script>
<script type="text/javascript" src="../bootstrap/js/bootstrap.min.js"></script>
</body>

</html>

上面的代码为每个导航链接指定data-toggle="tab"属性,告诉Bootstrap该链接用于切换标签页,还为每个导航链接指定了data-target属性,告诉Bootstrap该链接用于打开哪个标签页。

8.5 标签页

标签页和导航条的区别

本节所介绍的标签页和前一章所介绍的标签式导航、胶囊式导航非常相似,但二者存在一定的区别:
对于标签式导航、胶囊式导航,它们只是简单的导航链接;而本节所介绍的标签页并不用于导航,而是用于切换底部的内容面板
Bootstrap的标签页插件依赖transition.jsscrollspy.js库。这两个JS库包含在bootstrap.jsbootstrap.min.js中。

8.5.1 静态标签页

Bootstrap的标签页由如下两个部分组成。

  1. 导航组件:该导航组件与前面介绍的标签式导航、胶囊式导航完全相同。
  2. 内容面板:内容面板通常是一个被指定了class="tab-content"<div>元素,内容面板可以包含多个标签页,每个标签页又通常是一个被指定了class="tab-pane"<div>元素。

程序示例

了解了标签页的结构之后,接下来即可按该结构来构建静态标签页组件。如下代码构建了一个简单的标签页。

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
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title> 静态标签页 </title>
<link rel="stylesheet" href="../bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="../bootstrap/css/bootstrap-theme.min.css">
</head>

<body>
<div class="container">
<!-- 导航条 -->
<ul class="nav nav-tabs">
<li class="active"><a href="#">疯狂Java讲义</a></li>
<li><a href="#">疯狂Android讲义</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">前端图书
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="#">疯狂HTML 5讲义</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">疯狂前端开发讲义</a></li>
</ul>
</li>
</ul>
<!-- 内容面板 -->
<div class="tab-content">
<!-- 标签页 -->
<div class="tab-pane active">
<h3>疯狂Java讲义</h3>
<p>必读的Java学习经典,你懂的,不多说。</p>
</div>
<!-- 标签页 -->
<div class="tab-pane">
<h3>疯狂Android讲义</h3>
<p>最全面、最详细的Android学习图书,全面覆盖Android开发手册</p>
</div>
<div class="tab-pane">
<h3>疯狂HTML 5讲义</h3>
<p>全面、细致的前端开发基础图书,全面深入介绍HTML 5/CSS 3/JavaScript知识。</p>
</div>
<div class="tab-pane">
<h3>疯狂前端开发讲义</h3>
<p>前端开发的进阶图书,全面深入介绍jQuery/AngularJS/Bootstrap等框架。</p>
</div>
</div>
</div>
<script type="text/javascript" src="../jquery-3.1.1.js"></script>
<script type="text/javascript" src="../bootstrap/js/bootstrap.min.js"></script>
</body>

</html>

在这个示例中,前面部分代码定义了一个标签式导航,这个标签式导航与前一章介绍的并没有任何区别。后面部分代码则用于定义标签页的内容面板,需要为内容面板指定class="tab-content",对内容面板的每个标签页都需要指定class="tab-pane"样式
这里将标签式导航的第一个导航链接设为激活状态,同时也将内容面板中第一个标签页设为激活状态,这样即可使标签状态与标签页状态保持一致。
本示例的标签页是静态的,还不能响应用户的操作,因此标签页不会随着用户鼠标单击而切换。
提示:本示例中的标签页上面的导航链接下还嵌套了下拉菜单,实际上不嵌套下拉菜单也是允许的,而且更加简单。

8.4.2 使用JS实现滚动监听

除了可以使用data-spydata-target两个属性实现滚动监听之外,Bootstrap也支持使用JS实现滚动监听。

如何使用JS实现滚动监听

使用JS实现滚动监听只要调用scrollspy()方法即可,该方法有两种调用方法。

  1. 传入一个形如{target:#'fknavbar'}的对象参数,其中,target属性值指定滚动监听对应的导航条组件。
  2. 传入一个'refresh'字符串参数,其中,target属性值指定滚动监听对应的导航条组件。

如果被滚动监听的HTML元素存在增加、删除子元素的操作,则需要按如下方式调用scrollspy()方法。

1
2
3
$('[data-spy="scroll"]').each(function (){
var $spy=$(this).scrollspy('refresh');
})

下面代码示范了如何使用JS实现滚动监听。

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title> 滚动监听 </title>
<link rel="stylesheet" href="../bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="../bootstrap/css/bootstrap-theme.min.css">
<script type="text/javascript" src="../jquery-3.1.1.js"></script>
<script type="text/javascript" src="../bootstrap/js/bootstrap.min.js"></script>
</head>

<body style="padding-top:50px">
<div class="container">
<!-- 导航条 -->
<nav id="fknavbar" class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid">

<div class="navbar-header">
<!-- 匹配图标 -->
<a class="navbar-brand" href="#">滚动监听</a>
</div>
<!-- 导航条内容 -->
<ul class="nav navbar-nav">
<li class=""><a href="#java">疯狂Java讲义</a></li>
<li class=""><a href="#android">疯狂Android讲义</a></li>
<!-- 下拉菜单 -->
<li class="dropdown">
<!-- 触发按钮 -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">前端图书
<span class="caret"></span>
</a>
<!-- 菜单内容 -->
<ul class="dropdown-menu">
<li class="active"><a href="#html">疯狂HTML 5讲义</a></li>
<li role="separator" class="divider"></li>
<li><a href="#front">疯狂前端开发讲义</a></li>
</ul>
</li>
</ul>
</div>
</nav>
</div>
<h3 id="java">疯狂Java讲义</h3>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<h3 id="android">疯狂Android讲义</h3>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<h3 id="html">疯狂HTML 5讲义</h3>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<h3 id="front">疯狂前端开发讲义</h3>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<script type="text/javascript">
// 对body元素上进行滚动监听
$(document.body).scrollspy({
// 指定触发的导航
target: '#fknavbar',
offset: 180
});

// $('#fknavbar').on('activate.bs.scrollspy', function () {
// // 处理代码…
// });
</script>
</body>

</html>

该代码直接对页面的<body>元素进行滚动监听,但在页面中并未对<body>元素指定data-spydata-target两个属性,而是通过JS代码调用scrollspy()方法来实现对<body>元素的滚动监听。
为了保证页面滚动时滚动条不会消失,本例将滚动条设置为.navbar-fixed-top 风格,这意味着该滚动条始终固定在页面上方。由于滚动条固定在页面上方会遮挡页面的部分内容,因此还为<body>元素设置了padding-top:50px

滚动监听事件

Bootstrap为滚动监听也提供了一个事件:activate.bs.scrollspy,每当一个新的导航链接被激活时,该事件对应的监听函数都会被激发。例如可以使用如下代码来监听该事件:

1
2
3
$('#fknavbar').on('activate.bs.scrollspy', function () {
// 处理代码…
});

8.4 滚动监听

滚动监听实际上是一种页面内的导航方式。当页面内容很多时,开发者往往会在页面上方定义一系列导航链接,这些链接并不链接到其他页面,而是链接当前页面的锚点。当用户单击页面上方的链接时,页面将会自动定位到对应锚点所在的位置,这是Web页面开发中常用的技术。
滚动监听对这种导航进行了改进。如果用户在页面内容中通过滚动条进行滚动导航时,当用户滚动到某个锚点时,滚动监听会自动激活对应的导航链接,显示用户当前正在查看的位置。

8.4.1 通过data-*属性实现滚动监听

使用data-*属性实现滚动监听只要在被滚动的内容元素上指定两个属性即可,被滚动的内容元素可以是<div>元素或<body>元素。

属性 描述
data-spy 该属性的值始终是'scroll'字符串。
data-target 该属性的值用于指定对应的导航条,该属性值可以是任意的CSS选择器,通常会使用ID选择器。

程序示例

下面代码示范了如何使用data-*属性实现滚动监听。

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title> 滚动监听 </title>
<link rel="stylesheet" href="../bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="../bootstrap/css/bootstrap-theme.min.css">
<style type="text/css">
.scrollspy-content {
position: relative;
height: 160px;
overflow-y: scroll;
}
</style>
</head>

<body>
<div class="container">
<!-- 导航条 -->
<nav id="fknavbar" class="navbar navbar-default navbar-static">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">滚动监听</a>
</div>
<!-- 导航条 -->
<ul class="nav navbar-nav">
<!-- 定位到锚点 -->
<li class=""><a href="#java">疯狂Java讲义</a></li>
<li class=""><a href="#android">疯狂Android讲义</a></li>
<!-- 下拉菜单 -->
<li class="dropdown">
<!-- 下拉菜单展开收起按钮 -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">前端图书
<span class="caret"></span>
</a>
<!-- 菜单 -->
<ul class="dropdown-menu">
<li class="active"><a href="#html">疯狂HTML 5讲义</a></li>
<li role="separator" class="divider"></li>
<li><a href="#front">疯狂前端开发讲义</a></li>
</ul>
</li>
</ul>
</div>
</nav>
</div>
<div class="container">
<!-- data-spy="scroll"表示该容器可以滚动, -->
<!-- data-target="#fknavbar"指明控制滚动的导航条 -->
<!-- 1号代码 -->
<div data-spy="scroll" data-target="#fknavbar" class="scrollspy-content">
<h4 id="java">疯狂Java讲义</h4>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<h4 id="android">疯狂Android讲义</h4>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<h4 id="html">疯狂HTML 5讲义</h4>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<h4 id="front">疯狂前端开发讲义</h4>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
<p>s</p>
</div>
</div>
<script type="text/javascript" src="../jquery-3.1.1.js"></script>
<script type="text/javascript" src="../bootstrap/js/bootstrap.min.js"></script>
</body>

</html>

第一段代码使用<nav>元素定义了一个导航条,在该导航条内先定义了一个品牌图标(该品牌图标并没有导航作用),接下来程序在导航条内定义了3个导航项,其中第三个导航项其实包含了两个导航菜单项。从该导航条的代码来看,每个导航链接都会链接到相应的页面锚点—这与前面介绍的导航条并没有任何区别。
本例的关键在于页面中的1号代码,这行代码指定了data-spy="scroll"data-target="#fknavbar"属性,其中:

  • 第一个属性指定要对该元素执行滚动监听;
  • 第二个属性指定该元素对应的导航条为id为fknavbar的导航条。增加这一行之后,Bootstrap的导航监听插件就会发挥作用了。

为了让页面中被监听的<div>元素中出现滚动条,为该元素指定了.scrollspy-content 样式,该样式的代码如下:

1
2
3
4
5
.scrollspy-content {
position: relative;
height: 160px;
overflow-y: scroll;
}

该样式用于控制目标元素的高度只有160px,这是为了限制目标元素的高度,从而让目标元素上能出现滚动条。此外在该样式中还指定了**overflow-y:scroll,该属性用于设置在垂直方向上显示滚动条**。此外,对于被监听的组件,通常需要设置position:relative;,即采用相对定位的方式。
无论使用何种实现方式,被滚动监听的组件都应该采用相对定位的方式,也就是设置position:relative;。

如何对整个页面进行滚动监听

很多时候,开发者希望直接对页面内容整体进行滚动监听,这其实就是对<body>元素进行滚动监听,为此只要将data-spy="scroll"data-target="导航条选择器"这两个属性添加到<body>元素上即可。

8.3.3 下拉菜单事件

Bootstrap为下拉菜单提供了如下事件。

事件 描述
show.bs.dropdown 当下拉菜单开始显示时触发该方法。
shown.bs.dropdown 当下拉菜单显示完成时触发该方法。
hide.bs.dropdown 当下拉菜单开始隐藏时触发该方法。
hidden.bs.dropdown 当下拉菜单隐藏完成时触发该方法。

程序示例

如下代码示范了如何监听下拉菜单的事件。

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
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title> 下拉菜单的事件 </title>
<link rel="stylesheet" href="../bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="../bootstrap/css/bootstrap-theme.min.css">
<script type="text/javascript" src="../jquery-3.1.1.js"></script>
<script type="text/javascript" src="../bootstrap/js/bootstrap.min.js"></script>
</head>

<body>
<div class="container">
<!-- 普通下拉菜单 -->
<div class="dropdown">
<!-- 触发按钮 -->
<!-- 带有data-toggle="dropdown"属性的按钮可以展开或者收起下拉菜单 -->
<a class="btn btn-default dropdown-toggle" type="button" aria-haspopup="true" aria-expanded="true"
data-toggle="dropdown" id="dropMenu">
下拉菜单(带分隔条)
<span class="caret"></span>
</a>
<!-- 菜单 -->
<ul class="dropdown-menu">
<li><a href="#">新建</a></li>
<li><a href="#">打开</a></li>
<li><a href="#">保存</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">退出</a></li>
</ul>
</div>
</div>
<script type="text/javascript">
$(".dropdown").on("show.bs.dropdown", function (e) {
console.log("下拉菜单开始显示");
}).on("shown.bs.dropdown", function (e) {
console.log("下拉菜单显示完成");
}).on("hide.bs.dropdown", function (e) {
console.log("下拉菜单开始隐藏");
}).on("hidden.bs.dropdown", function (e) {
console.log("下拉菜单隐藏完成");
})
</script>
</body>

</html>

8.3.2 使用JS触发下拉菜单

如果希望通过JS展开下拉菜单,可调用下拉菜单的dropdown()方法,该方法有两个用法。

  1. 不传入参数:该方法默认打开下拉菜单。
  2. 传入'toggle'字符串参数:该字符串参数用于控制下拉菜单在打开或收起状态之间切换。

如下代码示范了如何使用JS触发下拉菜单。

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
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title> 触发下拉菜单 </title>
<link rel="stylesheet" href="../bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="../bootstrap/css/bootstrap-theme.min.css">
<script type="text/javascript" src="../jquery-3.1.1.js"></script>
<script type="text/javascript" src="../bootstrap/js/bootstrap.min.js"></script>
</head>

<body>
<div class="container">
<!-- 第1个按钮 -->
<button type="button" class="btn btn-primary">给下拉菜单注册展开方法</button>
<!-- 普通下拉菜单 -->
<div class="dropdown">
<!-- 下拉菜单的 触发按钮 -->
<a class="btn btn-default dropdown-toggle" type="button" aria-haspopup="true" aria-expanded="true"
id="dropMenu">
下拉菜单的触发按钮
<span class="caret"></span>
</a>
<!-- 菜单 -->
<ul class="dropdown-menu">
<li><a href="#">新建</a></li>
<li><a href="#">打开</a></li>
<li><a href="#">保存</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">退出</a></li>
</ul>
</div>
</div>
<script type="text/javascript">
// filter(表达式):从jQuery对象中返回匹配表达式的DOM元素,删除不匹配的DOM元素
// 点击第1个按钮时
$(".btn").filter(".btn-primary").click(function () {
// 给下拉列表的 触发按钮 注册展开方法
// 1号代码
$("#dropMenu").dropdown();
});
</script>
</body>

</html>

上面程序中第二个按钮上没有data-toggle="dropdown"属性,因此用户直接单击第二个按钮时不会展开下拉菜单。
这个时候需要给下拉菜单的触发按钮注册展开方法,这通过在触发按钮上调用dropdown()方法实现。
运行程序,先点击第1个按钮,把dropdown()方法绑定到下拉菜单的触发按钮上,然后才可以通过点击这个触发按钮展开下拉菜单.

JS展开下拉菜单步骤

上面的代码中给触发按钮注册dropdown()方法后,下拉菜单的触发按钮只能展开下来菜单,之后再次点击触发按钮,无法关闭下来菜单。实际上这样做并没有什么意义,仅仅只是方便我们更好地了解通过JS触发下拉菜单的原理:
要先在下拉菜单的触发按钮上调用dropdown()方法进行注册,然后该触发按钮才可以展开菜单.

读者小蓝注

通过JS好像只能展开下拉菜单,展开后好像还无法收起下拉菜单。
如果要支持收起菜单,一定要在触发按钮上添加data-toggle="dropdown"属性,但是问题就是,如果添加了该属性,则直接点击触发按钮就可以展开或者收起下拉菜单了.也就没有JS什么事情了.所以还是不要使用JS来触发下来菜单的好,直接使用data-toggle="dropdown"属性即可.
注意,这个地方还存在疑惑,有空再弄清楚吧。

8.3 下拉菜单

前面在介绍导航和按钮时介绍了下拉菜单的用法,主要是使用data-*属性来触发下拉菜单。本节将会介绍使用JS脚本触发下拉菜单。此外,本节会更系统地归纳下拉菜单的用法。
Bootstrap 的对话框插件依赖transition.jsdropdown.js 库。这两个JS 库都包含在bootstrap.jsbootstrap.min.js中。

8.3.1 使用data-*属性触发下拉菜单

使用data-*属性触发下拉菜单时只需要指定一个属性。

属性 描述
data-toggle 将该属性指定为dropdown即可。
不管是普通下拉菜单,还是按钮式下拉菜单,还是导航中的下拉菜单,都只需指定data-toggle="dropdown"即可触发下拉菜单。在这种方式下,由于不需要在事件源上指定触发哪个下拉菜单,因此**Bootstrap要求将触发事件源的按钮或链接与下拉菜单定义在同一个容器内**。

程序示例

下面代码示范了三种下拉菜单的触发方式。

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
66
67
68
69
70
71
72
73
74
75
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title> 触发下拉菜单 </title>
<link rel="stylesheet" href="../bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="../bootstrap/css/bootstrap-theme.min.css">
</head>

<body>
<div class="container">
<!-- 导航条 -->
<ul class="nav nav-tabs">
<li role="presentation"><a href="#">主页</a></li>
<!-- class="dropdown"表示该标签是下拉菜单的容器 -->
<li role="presentation" class="dropdown">
<!-- data-toggle="dropdown"属性使得该链接可以触发下拉菜单 -->
<!-- 触发按钮要和下来菜单放在同一个容器下 -->
<a class="dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true"
aria-expanded="true">
课程体系 <span class="caret"></span>
</a>
<!-- 使用ul添加下拉菜单 -->
<ul class="dropdown-menu">
<li><a href="#">Java基础强化营</a></li>
<li><a href="#">全栈式程序员就业营</a></li>
<li><a href="#">全栈式程序员突击营</a></li>
</ul>
</li>
<li role="presentation" class="active"><a href="#">师资介绍</a></li>
<li role="presentation"><a href="#">教育理念</a></li>
<li role="presentation" class="disabled"><a href="#">退出系统</a></li>
</ul>
<!-- class="dropdown"表示该标签是下拉菜单的容器 -->
<div class="dropdown">
<!-- data-toggle="dropdown"表示该按钮可以触发下来菜单 -->
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="true">
下拉菜单(带分隔条)
<span class="caret"></span>
</button>
<!-- class="dropdown-menu"表示该列表是下拉菜单 -->
<ul class="dropdown-menu">
<li><a href="#">新建</a></li>
<li><a href="#">打开</a></li>
<li><a href="#">保存</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">退出</a></li>
</ul>
</div>
<!-- 按钮组式下拉菜单 -->
<div class="btn-group">
<!-- data-toggle="dropdown"表示该按钮可以触发下拉菜单 -->
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="true">
按钮式下拉菜单(带分隔条)
<span class="caret"></span>
</button>
<!-- 下拉菜单 -->
<ul class="dropdown-menu">
<li><a href="#">新建</a></li>
<li><a href="#">打开</a></li>
<li><a href="#">保存</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">退出</a></li>
</ul>
</div>
</div>
<script type="text/javascript" src="../jquery-3.1.1.js"></script>
<script type="text/javascript" src="../bootstrap/js/bootstrap.min.js"></script>
</body>

</html>

在该代码中定义了3个下拉菜单,分别是导航中的下拉菜单、普通下拉菜单和按钮式下拉菜单。
不管是哪种下拉菜单,我们都:

  • 将触发下拉菜单的按钮和链接与下拉菜单定义在同一个容器中,
  • 并为按钮和链接指定data-toggle="dropdown"属性,这样使用该按钮或链接即可打开下拉菜单。