需求
页面上有一排按钮,悬浮在窗口顶端,不随页面滑动而滑动,这一组按钮分别对应的是页面的各个部分,点击按钮,页面定位到对应的位置。
需求分析
拿到这个需求,很自然的想到,解决这个最简单的方法是使用锚点(能靠HTML和css解决的,尽量不使用js
解法
想到使用锚点事情就比较简单了,借用a标签的href定位,很快就写了一个Demo,
完整代码:https://codepen.io/yangyang11...
关键代码:
<div id="content">
<div class="btn-container">
<a class="btn" href="#anchor1">锚点1</a>
<a class="btn" href="#anchor2">锚点2</a>
<a class="btn" href="#anchor3">锚点3</a>
</div>
<div id="anchor1" class="anchor-con">anchor1</div>
<div id="anchor2" class="anchor-con">anchor2</div>
<div id="anchor3" class="anchor-con">anchor3</div>
</div>
这时候,点击悬浮的button,页面可以实现快速定位。
坑1
点了几遍之后立马就发现了一个坑,因为按钮是悬浮的,而锚点定位,默认是定位到窗口顶端,这样定位到的区域就会有一部分被悬浮的按钮挡住
如下图:
原始状态:
点击“锚点1”按钮之后(黄色框起来的部分就是被遮盖起来的部分):
由此引出一个问题,怎么使a标签的锚点不定位到窗口最顶端?
怎么使a标签的锚点定位到窗口的任意位置
方法1:
网上搜了一些方法,其中有提到使用:target,主要添加几行css
#anchor1:target, #anchor2:target, #anchor3:target {
padding-top: 100px; // 这里更改padding-top的值使其定位到不同地方
}
效果如下图:
虽然可以实现文字的不被遮挡,但是实际上,对于固定大小的div来说,很容易影响div的内部布局,故不适用我这里的情况(然而这里的:target在其他地方作用还是非常大的。
方法二
换别的思路,想了个巧办法,在每个需要定位的节点前面加一个辅助节点,辅助节点的高度可以自定,锚点的实际定位的是这个辅助节点
完整代码:https://codepen.io/yangyang11...
关键代码:
<div class="btn-container">
<a class="btn" href="#anchor1">锚点1</a>
<a class="btn" href="#anchor2">锚点2</a>
<a class="btn" href="#anchor3">锚点3</a>
</div>
<div class="anchor-con anchor1">
<!--实际上定位的是这个辅助节点-->
<div id="anchor1" class="assist-div"></div>
anchor1
</div>
<div class="anchor-con anchor2">
<div id="anchor2" class="assist-div"></div>
anchor2
</div>
<div class="anchor-con anchor3">
<div id="anchor3" class="assist-div"></div>
anchor3
</div>
辅助节点的css:
.assist-div {
width: 1px;
height: 1px;
position: absolute;
top: -100px; // 这里可以设任意高度 对应锚点最后离窗口顶端的距离
left: 0;
}
这个方法的优点:
(一)辅助节点可以绝对定位 不影响布局
(二)改变辅助节点的top值 可以实现锚点定位到窗口任意位置
最后效果截图:(点击了“锚点2“按钮)
坑2
正当我美滋滋的交付任务,坐等1h之后的聚餐的时候,PM来找我说,不行,移动端打开的时候,我切换点了几下悬浮的按钮之后,要点很多下返回键才能退出页面。
我:对啊因为每点一次按钮就在浏览器记录里面添加一条记录
PM:这不行 需要解决掉
。。。
这是个问题,需要用户点击很多下才能退出页面体验确实不好,如果想要用户点击一次就退出页面,就得始终保持history只有一条记录,但是a标签跳转的话自动往history加一条记录,我也不能对此做什么。
。。。
这时候不得不使用js了,
我盯着锚点看了会儿(实际上看了半小时:) )发现:
例如http://shili.com/Demo.html#content1 这样的url,是可以直接定位到http://shili.com/Demo.html 这个页面的id为content1的节点处的,这样的话,我不使用a标签,直接使用js去动态改变url后面的#id 的id,也可以实现定位的效果,并且还能实现浏览器只保存一条记录。
完整代码:https://codepen.io/yangyang11...
关键代码:
去除a标签,改为使用div,并添加click:
<div class="btn-container">
<div class="btn" onclick="goToAnchor('#anchor1')">锚点1</div>
<div class="btn" onclick="goToAnchor('#anchor2')">锚点2</div>
<div class="btn" onclick="goToAnchor('#anchor3')">锚点3</div>
</div>
function goToAnchor(anchorId) {
// 使用replace方法可以保证前一次浏览不会在浏览器中保留记录
window.location.replace(window.location.href.split('#')[0] + anchorId);
}
至此,需求就完成了。
但是就页面定位到指定位置其实还有更好的办法,就是使用js去获取指定位置的offsetTop,这样的话还可以加滑动动画,使定位的这个过程比较平滑。我没有使用这个方法是因为,一我开始就一心想使用锚点结果只能遇坑填坑,二我的页面中有很多折叠的部分(类似于手风琴效果),所以每次的offsetTop都可能是不一样的,点击时都需要去获取offsetTop的值再移动,比较麻烦而且耗性能。(emmm虽然我一开始就抗拒使用js去解决,最后还是使用了,但是抉择之下还是使用性能消耗小的比较好
这里也丢一下采用上面这个方法的关键代码
document.getElementById('content').scrollTop = document.getElementById(anchorId).offsetTop - 100;
2019.3.26日更新
使用js去实现的话,还有一种方法,使用:Element.scrollIntoView方法,我试了下,这个方法也很好用,还可以自定义滑动方式,性能上,相较于上面的js方法要好,代码如下:
<!DOCTYPE html>
<html>
<head>
<title>测试</title>
<style type="text/css">
html, body {
width: 100%;
height: 100%
}
</style>
</head>
<body>
<div style="width: 100%;height: 100%;background: red" onclick="scrollToView()"></div>
<div id="scroll" style="width: 100%;height: 100px;background: blue;"></div>
<div style="width: 100%;height: 100%;background: red"></div>
<script type="text/javascript">
function scrollToView () {
document.getElementById('scroll').scrollIntoView({
block: 'start',
inline: 'nearest',
behavior: 'smooth'
})
}
</script>
</body>
</html>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。