使用 Bootstrap 3 实现带 Affix 滚动固定的 ScrollSpy 侧边导航

本文介绍如何使用 Bootstrap 3 的 ScrollSpyAffix 插件,构建一个具有顶部导航、巨幕信息区、左侧滚动固定导航和内容同步高亮的页面,并使用 JavaScript 方式代替传统的 data-spy 属性完成初始化。

📌 背景与目标

在 Bootstrap 3 中,ScrollSpy 插件可根据页面滚动自动更新导航高亮,Affix 插件可实现元素滚动到特定位置后固定在页面上。这两个功能组合后,可以实现如下交互式页面结构:

  • 顶部固定导航栏(navbar-fixed-top)
  • 巨幕欢迎区(Jumbotron)
  • 左侧导航与右侧内容共用一个 .container
  • 左侧导航随着滚动固定在页面顶部
  • 当前滚动位置自动在导航中高亮显示

✅ 技术选型

技术 用途
Bootstrap 3 UI 框架,提供 ScrollSpy 和 Affix 插件
jQuery 事件监听、DOM 操作
ScrollSpy 实现滚动监听和导航高亮切换
Affix 实现滚动触发元素“吸顶”固定

🧱 页面结构说明

页面采用 Bootstrap 栅格布局,左侧为导航栏 col-sm-3,右侧为内容区域 col-sm-9,整体包含在 .container 内部。

1
2
3
4
5
6
7
8
9
10
<div class="container">
<div class="row">
<div class="col-sm-3">
<!-- 左侧导航 -->
</div>
<div class="col-sm-9">
<!-- 内容区 -->
</div>
</div>
</div>

✨ 效果展示图(逻辑结构)

1
2
3
4
5
6
7
8
9
10
+-----------------------------+
| 顶部导航(fixed-top) |
+-----------------------------+
| 巨幕信息区(jumbotron) |
+-----------------------------+
| container |
| +-------+ +-------------+ |
| | nav | | content | |
| +-------+ +-------------+ |
+-----------------------------+

🔧 核心代码实现

✅ HTML 结构(关键部分)

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 左侧导航 -->
<nav id="sidebarNav" class="nav nav-pills nav-stacked">
<ul class="nav">
<li><a href="#section1">部分 1</a></li>
<li><a href="#section2">部分 2</a></li>
...
</ul>
</nav>

<!-- 内容区域 -->
<div id="section1">...</div>
<div id="section2">...</div>

✅ JavaScript 初始化(无需 data-spy)

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
<script>
$(function () {
var navbarH = $(".navbar").outerHeight(true);
var jumbotronH = $(".jumbotron").outerHeight(true);
console.log(navbarH, jumbotronH);

$("#sidebarNav").affix({
offset: {
top: function () {
var top = navbarH + jumbotronH;
return (this.top = top);
},
bottom: function () {
var bottom = $("footer").outerHeight(true);
return (this.bottom = bottom);
},
},
});
// 手动触发 scrollspy 监听
$("body").scrollspy({
target: "#sidebarNav",
offset: navbarH + jumbotronH,
});
});
</script>

🎯 Affix 固定导航实现说明

核心点:

1
2
3
4
5
6
<nav
id="sidebarNav"
data-spy="affix"
data-offset-top="260"
data-offset-bottom="200"
></nav>

等同

1
2
3
4
5
6
7
8
9
10
<script>
$(function () {
$("#sidebarNav").affix({
offset: {
top: 260,
bottom: 200,
}
});
});
</script>
属性 说明
data-spy="affix" 启用 Affix 插件
data-offset-top 触发固定的页面纵向偏移量(以 px 为单位)
data-offset-bottom 在页面底部取消固定,避免覆盖页脚

.affix 样式定义:

1
2
3
4
#sidebarNav.affix {
top: 70px;
width: 220px;
}

Demo代码

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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
<!DOCTYPE html>
<html lang="zh-CN">

<head>
<meta charset="UTF-8">
<title>Bootstrap3 ScrollSpy + Affix 示例</title>
<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Bootstrap 3 样式 -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">

<style>
body {
position: relative;
padding-top: 70px;
}

.jumbotron {
margin-bottom: 30px;
}

#sidebarNav.affix {
top: 70px;
/* 与顶部 navbar 高度一致 */
width: 220px;
}

.scroll-section {
height: 500px;
padding: 20px;
background: #f5f5f5;
border: 1px solid #ccc;
margin-bottom: 20px;
}
</style>
</head>

<body>

<!-- 顶部导航栏 -->
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">我的网站</a>
</div>
<ul class="nav navbar-nav">
<li class="active"><a href="#section1">部分1</a></li>
<li><a href="#section2">部分2</a></li>
<li><a href="#section3">部分3</a></li>
<li><a href="#section4">部分4</a></li>
</ul>
</div>
</nav>

<!-- 巨幕信息 -->
<div class="container">
<div class="jumbotron">
<h1>欢迎访问!</h1>
<p>这是一个 ScrollSpy + Affix 示例。</p>
</div>
</div>

<!-- 主体区域 -->
<div class="container">
<div class="row">

<!-- 左侧导航 -->
<div class="col-sm-3">
<nav id="sidebarNav">
<ul class="nav nav-pills nav-stacked">
<li class="active"><a href="#section1">部分1</a></li>
<li><a href="#section2">部分2</a></li>
<li><a href="#section3">部分3</a></li>
<li><a href="#section4">部分4</a></li>
</ul>
</nav>
</div>

<!-- 内容区 -->
<div class="col-sm-9">
<div id="section1" class="scroll-section">
<h2>部分 1</h2>
<p>这里是部分1的内容。</p>
</div>
<div id="section2" class="scroll-section">
<h2>部分 2</h2>
<p>这里是部分2的内容。</p>
</div>
<div id="section3" class="scroll-section">
<h2>部分 3</h2>
<p>这里是部分3的内容。</p>
</div>
<div id="section4" class="scroll-section">
<h2>部分 4</h2>
<p>这里是部分4的内容。</p>
</div>
</div>

</div>
</div>

<footer>
这是底部内容
</footer>

<!-- 脚本 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>

<script>
$(function () {

var navbarH = $('.navbar').outerHeight(true);
var jumbotronH = $('.jumbotron').outerHeight(true);
console.log(navbarH, jumbotronH);

$('#sidebarNav').affix({
offset: {
top: function () {
var top = navbarH + jumbotronH;
return (this.top = top);
},
bottom: function () {
var bottom = $('footer').outerHeight(true);
return (this.bottom = bottom);
}
}
});
// 手动触发 scrollspy 监听
$('body').scrollspy({ target: '#sidebarNav', offset: navbarH + jumbotronH });
});
</script>
</body>

</html>
坚持原创技术分享,您的支持将鼓励我继续创作!
0%