菜单与内容联动
- 实现思路
菜单是拥有点击事件 -->采用锚点跳到对应内容
内容跳转到菜单 --> scroll 滚动事件 计算锚点的offset 和pageYoffset
给对应菜单目录添加样式
2.实现
为了给不熟悉ES6语法读者更好的体验,代码全部都使用ES5
<!DOCTYPE html><html><head></head>
<style>
/*菜单容器样式,设置水平垂直居中,方便点击*/
.menu{position: fixed;width: 200px;height: 200px;top: 50%;left: 50%;transform: translate(-50%,-50%);}
/*菜单样式*/
[href]{display: inline-block;width: 40px;}
/*内容的样式*/
[name]{display: block;width: 300px;height: 400px;border-top: 5px solid salmon;}
/*菜单高亮的样式*/
.active{font-size: 32px;background-color: chartreuse;}
</style>
<body>
<!--内容容器-->
<div class="content"></div>
<!--菜单容器-->
<div class="menu"></div>
</body></html><script>
//初始化选择器,将获取到的element数组转化为数组对象
function $(selector){
return Array.prototype.slice.call(document.querySelectorAll(selector))//支持css3的选择器
}
//创建内容和菜单的DOM
function createDom(attr){
var html = '';
var temp = attr=='href'?'#':'';
for (var i=1;i<10;i++) {
html+='<a '+attr+'="'+(temp+i)+'">'+i+'</a>';
}
return html;
}
$('.content')[0].innerHTML = createDom('name')
$('.menu')[0].innerHTML = createDom('href')
//获取内容的偏移量(相对于浏览器顶部)
var nameOffsets = $('[name]').map(function(v){
return v.offsetTop
});
window.onscroll = function(e){
//获取当前页面相对于浏览器顶部的偏移量
var pageOffset = window.pageYOffset;
var abs = Math.abs; //获取绝对值函数
//查找离当前浏览器顶部的偏移量最近的菜单锚点.
var nearHash = nameOffsets.reduce(function(a,b){
return abs(a-pageOffset)>abs(b-pageOffset)?b:a;
})
//获取菜单锚点
var index = nameOffsets.indexOf(nearHash);
//给菜单锚点添加 .active ,移除其他菜单元素的.active
$('.active').forEach(function(v){
v.className=''
})
$('[href]')[index].className = 'active'
}
</script>
3.思考
实现方式的优化
onscroll 应该使用throttle 做一个节流,或者使用debounce触发最后一次即可,减少计算的次数..
动态内容解决方案,
将nameOffsets 这个数组在scroll里面获取,这样每次都会重新获取对应的内容的位置,动态内容也能准确定位
未解决的问题,没有考虑id 锚点的情况,没有考虑锚点隐藏(display:none)的情况,
4.总结
实现方式有些粗糙,但也不乏是一种解决思路,针对大多数情况来说,这个已经可以解决问题,缺陷确实难免,毕竟是有感而发,随意为之,后续有时间再来改进.