页面上有一排按钮,悬浮在窗口顶端,不随页面滑动而滑动,这一组按钮分别对应的是页面的各个部分,点击按钮,页面定位到对应的位置。javascript
拿到这个需求,很天然的想到,解决这个最简单的方法是使用锚点(能靠HTML和css解决的,尽可能不使用jscss
想到使用锚点事情就比较简单了,借用a标签的href定位,很快就写了一个Demo,
完整代码:https://codepen.io/yangyang11...
关键代码:html
<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,页面能够实现快速定位。java
点了几遍以后立马就发现了一个坑,由于按钮是悬浮的,而锚点定位,默认是定位到窗口顶端,这样定位到的区域就会有一部分被悬浮的按钮挡住
以下图:
原始状态:
点击“锚点1”按钮以后(黄色框起来的部分就是被遮盖起来的部分):
由此引出一个问题,怎么使a标签的锚点不定位到窗口最顶端?json
网上搜了一些方法,其中有提到使用: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“按钮)测试
正当我美滋滋的交付任务,坐等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>