0%

锚点定位导航

一般我们翻阅百科的时候,如果文章过长的话,就不太方便找到我们想要的资源。此时有一个定位导航的话,那可真是帮大忙了~今天,就来聊聊这种常见的锚点定位导航的原理以及是如何实现的。


定位原理

首先我们来了解一下,什么锚点?

在海上,水手们会将锚丢入海中,或者靠岸时将锚抛上岸,其固定目的是让船固定位置。而**锚点(anchor)**也是一样,只不过场景不同罢了。

页面锚点定位可以通过name或者id属性来定位。name已经被HTML5废弃了,就不再多提。

在页面上,每个id都会自动创建一个锚点,同时还会生成一个hash,表示所处的文档位置。浏览器可以通过hash来确定位置,使用的方式一般如下:

1
2
3
4
<a href="#title">跳到title</a>

<!-- 地址栏后会加上一段 # 开头的 hash -->
<!-- https://anran758.github.io/blog/#title -->

这个hash值我们可以通过浏览器的APIlocation.hash取到。但值得注意的是,跳转hash的话是不会像服务端发送请求的(除了第一次请求页面)。

深入分析

但我们光知道跳转的原理可不够,只要你尝试了上面的跳转方法后,你会发现浏览器跳转方式是很唐突的。它会直愣愣的跳到指定位置(或者没有找到指定位置会,跳到页面最上面),这在用户看来是十分生硬的,在体验上这个交互并不太友好。这时产品就会要求我们对此处进行优化~ 不过知道了上面的原理后,我们也可以直接使用js的方式来代替这种原生的默认跳转:

首先我们页面的结构大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<nav class="nav">
<a class="actived" href="#title1">第一组图片</a>
<a href="#title2">第二组图片</a>
<a href="#title3">第三组图片</a>
</nav>

<main id="content">
<article id="title1" class="item">
<!-- 许多内容 -->
</article>

<article id="title2" class="item">
<!-- 许多内容 -->
</article>

<article id="title3" class="item">
<!-- 许多内容 -->
</article>
</main>

页面布局固定了后,元素离页面顶部的距离可以通过offsetTop来获取到。同时我们可以操作滚动容器(html)的scrollTop来修改滚动位置。嘿,这样一上(目标距离顶部的高度)一下(滚动条),两个API双剑合璧后,我们就可以点击模拟滚动啦..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// jquery 环境
var $menu = $('.nav');
var $menuList = $menu.find('a');

// 给超链接绑定点击事件
$menuList.each(function() {
var $this = $(this);
$this.click(function(e) {
var id = $this.attr('href').replace(/#/g, '');

// 获取目标距离顶部的高度
var top = $('#' + id).offset().top - 60;

// 给滚动容器加动画的效果,滚动到目标位置
$('html').animate({ scrollTop: top }, 1000);
});
});

蹡蹡!在页面中调试会发现,点击后页面会平滑的滚动到指定的锚点~ 除此之外,我们还得再添加一个功能:在页面滚动的时候,能让用户知道自己所在的位置~

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
var contentList = $('#content').find('.item');

$(window).scroll(function(e) {
var top = $(document).scrollTop();

// 获取目前滚动条所处的区间
var currentID = '';
contentList.each(function() {
var $this = $(this);

// 获取当前距离顶部的数值
var itemTop = $this.offset().top;

// 如果当前滚动距离已经进入了 item 的区间
if (top > itemTop - 250) {
currentID = '#' + $this.attr('id');
} else {
return false;
}
});

var currentLink = $menu.find('.actived');
// 移除其他的类名
if (currentID && currentLink.attr('href') !== currentID) {
currentLink.removeClass('actived');

$menu.find("[href='" + currentID + "']").addClass('actived');
}
});

这样就锚点定位导航的功能就大功告成啦~ 最后将测试代码放入了codepen上了,感兴趣的同学可以去看看。

「请笔者喝杯奶茶鼓励一下」

欢迎关注我的其它发布渠道