效果图
实现过程
因为生成一级导航菜单我在另外一篇文章里写过,本文会省略一些重复的东西,需要查看的请移步自动生成右侧导航栏,页面滚动时标签高亮。
1、html页面结构
<div class="content" id="article">
<h2>美食</h2>
<h4>鱼香肉丝</h4>
<h4>油焖小龙虾</h4>
<p>酸菜鱼</p>
<h2>人文</h2>
<h4>蜀绣</h4>
<p>陶瓷</p>
<h4>丝绸</h4>
<p>油画</p>
<h2>影视</h2>
<h4>风雨哈佛路</h4>
<h4>泰坦尼克号</h4>
<p>肖申克的救赎</p>
</div>
<div class="right-nav">
<p>导航</p>
<div id="nav"></div>
</div>
2、自动生成导航栏
根据页面中的h2和h4标签生成导航目录。
var html = ['<ul>'];
var headings = document.querySelectorAll('#article h2');
for(var i = 0; i < headings.length; i++) {
var id = 'd' + i;
var el = headings[i];
var title2_num = 0; //记录该一级菜单下的二级菜单的个数
el.id = id;
//生成一级目录
html.push('<li><a href="'+el.childNodes[1].href+ '" id = "'+'a' + i + i+'">'+(i+1)+'. '+el.firstChild.nodeValue+'</a>');
var parent = headings[i].parentElement.parentElement;
var element = parent.firstElementChild;
while(element != headings[i].parentElement) { //找到当前的h2标签
element = element.nextElementSibling;
}
//生成二级目录
while(1){
if( (element == parent.lastElementChild) || ((i<headings.length-1) &&(element == headings[i+1].parentElement))) {
// console.log('break');
break;
}
element = element.nextElementSibling;
var level2_title = element.querySelectorAll('h4');
var len = 0;
for(len=0; len< level2_title.length; len++){
level2_title[len].id = 'd'+i + ''+title2_num;
html.push('<li><a href="#' +level2_title[len].id+ '" id = "a' +i +''+ i+ ''+ title2_num +''+
title2_num+ '" class="level2_a">'+(i+1)+'.'+(title2_num+1)+' '
+level2_title[len].firstChild.nodeValue+'</a></li>');
}
title2_num = title2_num + level2_title.length;
}
level2_title_length.push(title2_num);
}
var nav = document.getElementById('nav');
nav.innerHTML = html.join('\n');
3、页面滚动导航标签高亮
滚动条滚动到不同内容块时相应的导航标签高亮。
$(function(){
$(window).scroll(function(){
var wst = $(window).scrollTop(); //滚动条距离顶部距离页面顶端的值
var title = document.querySelectorAll('#article h2');
for(var i=0; i<title.length; i++){
if($("#d"+i).offset().top <= wst){
$('#nav a').removeClass("c");
$('#a'+i+i).addClass("c");
}
for(var j=0; j<level2_title_length[i];j++){
if($("#d"+i+j).offset().top <= wst){
$('#nav a').removeClass("c");
$('#a'+i+i+j+j).addClass("c");
}
}
}
});
});
4、点击导航标签时高亮
$('#nav a').click(function(e){
setTimeout(function(){
$('#nav a').removeClass("c");
$(this).addClass("c");
if( e.target.getAttribute("class") == null) {
e.target.setAttribute("class", "c");
} else {
e.target.setAttribute("class", e.target.getAttribute("class")+ ' '+"c");
}
},0)
});
至于这里为什么会使用一个延时函数,你可以把函数去掉看看效果?
是因为点击标签发生页面间的跳转,滚动条的位置发生变化,又会触发$(window).scroll()
函数,但是经过该函数自动计算出的标签并不是点击的标签,所以需要加一个延时函数,让点击事件的响应函数结果覆盖掉滚动条滚动事件的函数效果。
在下才疏学浅,只能想到这样的解决方案了,如有大神指路,不胜感激~
源码
这个页面的完整代码是:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>anchor-nav</title>
<style>
html, body {
width: 100%;
height: 100%;
box-sizing: border-box;
text-align: center;
}
.content {
width:800px;
margin: 0 auto;
margin-top: 100px;
}
.content h2 {
font-size: 18px;
color:rgba(0,0,0,.87);
height: 600px;
line-height: 600px;
background-color: deepskyblue;
}
.content h4 {
font-size: 16px;
color:rgba(0,0,0,.87);
background-color: lightskyblue;
height: 400px;
line-height: 400px;
}
.content p{
font-size: 12px;
color:#666;
height: 400px;
line-height: 400px;
background-color: skyblue;
}
.right-nav {
position: fixed;
right:20px;
top:200px;
width: 200px;
text-align: left;
}
.right-nav p {
color:#333;
}
.right-nav ul {
padding-left: 0;
}
.right-nav li{
list-style: none;
}
.right-nav a {
color:#999;
padding-left:6px ;
border-left: 2px solid #999;
display: inline-block;
margin-bottom: 4px;
text-decoration: none;
}
.right-nav .level2_a {
color:#999;
padding-left:20px ;
border-left: 2px solid #999;
}
.right-nav a:hover{
color:#2277da;
}
.right-nav .c{
border-left: 2px solid #2277da;
color:#2277da;
}
</style>
</head>
<body>
<h1>anchor-nav</h1>
<div class="content" id="article">
<h2>美食</h2>
<h4>鱼香肉丝</h4>
<h4>油焖小龙虾</h4>
<p>酸菜鱼</p>
<h2>人文</h2>
<h4>蜀绣</h4>
<p>陶瓷</p>
<h4>丝绸</h4>
<p>油画</p>
<h2>影视</h2>
<h4>风雨哈佛路</h4>
<h4>泰坦尼克号</h4>
<p>肖申克的救赎</p>
</div>
<div class="right-nav">
<p>导航</p>
<div id="nav"></div>
</div>
<script type="text/javascript" src="jquery-1.11.3.min.js"></script>
<script>
var h4_length = [];
window.onload = function () {
/* 1、创建右侧导航栏*/
var html = ['<ul>'];
var h2 = document.querySelectorAll('#article h2');
for(var i = 0; i < h2.length; i++) {
var id = 'd' + i;
var el = h2[i];
el.id = id;
var h4_num = 0; //记录该一级菜单下的二级菜单的个数
// 1.1 生成一级目录
html.push('<li><a href="#'+ id + '" id="'+ 'a' + i + i +'">' + (i + 1) + '.' + el.innerHTML + '</a></li>');
// 1.2 生成二级目录
/* 生成二级目录需要从两个h2标签中找到所有的h4标签*/
var parent = h2[i].parentElement;
var element = h2[i];
while(1) {
if( (element == parent.lastElementChild) || (element == h2[i+1])) {
break; //搜索结束
}
element = element.nextElementSibling;
// console.log(element.tagName.toLowerCase());
if(element.tagName.toLowerCase() == 'h4') {
element.id = 'd' + i + h4_num;
html.push('<li><a href="#' + element.id + '" id="a' + i + '' + i + ''+ h4_num + '' + h4_num + '" class="level2_a">' + (i+1) + '.' + (h4_num+1)+ ' '+element.innerText + '</a></li>');
h4_num = h4_num + 1;
}
}
h4_length.push(h4_num);
}
html.push('</ul>');
var nav = document.getElementById('nav');
nav.innerHTML = html.join('\n');
/* 2、点击时激活右侧导航*/
$('#nav a').click(function(e){
setTimeout(function(){
$('#nav a').removeClass("c");
if( e.target.getAttribute("class") == null) {
e.target.setAttribute("class", "c");
} else {
e.target.setAttribute("class", e.target.getAttribute("class")+ ' '+"c");
}
},0);
});
}
/* 3、滚动时激活右侧导航 */
$(function(){
$(window).scroll(function(){
var wst = $(window).scrollTop(); //滚动条距离顶部距离页面顶端的值
var h2 = document.querySelectorAll('#article h2');
for(var i=0; i<h2.length; i++){
if($("#d"+i).offset().top <= wst){
$('#nav a').removeClass("c");
if( !$('#a'+i+i).hasClass("c")) {
$('#a'+i+i).addClass("c");
}
}
for(var j = 0; j < h4_length[i]; j++){
if($("#d"+i+j).offset().top <= wst){
$('#nav a').removeClass("c");
$('#a'+i+i+j+j).addClass("c");
}
}
}
});
});
</script>
</body>
</html>
不想复制的可以去我的github上下载,送免费飞机票,如果喜欢,不妨star一下吧。
后话
工作快三个月了,学习的热情也有点降低。多写点文章不仅可以记录遇到的问题,方便以后查看,还可以督促自己学习,不失为一个保持学习热情的好方法,如果有好方法的话还请不吝赐教。