js的各种offsetXXX和scrollXXX的介绍非常多,其使用也非常广泛,特别是在需要对页面定位的时候,最近实现一个简单的目录点击定位内容及滚动屏幕定位目录标题的小功能,完全是靠这两个属性实现,当然事件监听啥的,这肯定是必要的。
直接上代码:
一、页面滚动,自动定位目录:
//滚动页面目录自动定位显示
let autoActive = function(){
let html_top = document.getElementsByTagName("html")[0].scrollTop; //获得父级卷去的高度
//标题自动定位
for (let i = 0 ;i < h3_len ; i++) {
//父级卷去高度与对应文字标题距离顶部高度对比,小于说明对应标题显示在可视口内
if (html_top <= h3_eles[i].offsetTop) {
//省略获得目录列表中对应index的列表内容,并添加激活样式,删除其他列表项激活样式代码
break;
}
}
};
document.addEventListener("scroll",autoActive);
上面是滚动屏幕根据卷去的内容,自动定位目录列表中相应的标题,核心就是比对父级卷去高度与相应标题距顶部的高度(此处以html为父级)如果小于,则说明当前标题可视,则改变目录中对应的样式即可,注意事件绑定与事件处理函数的分离,后续需要有其他操作。
二、点击目录,定位页面内容
//点击目录切换函数其中变量为已经定义好的DOM节点,根据需要自行定义即可
let switchCatalog = function(e){
//点击时取消滚动事件,防止冲突
document.removeEventListener("scroll",autoActive);
let index = e.target.index;
//激活切换
e.target.className += " active-catalog";
//取消其他对应列表的样式
for (let i = 0; i< a_len;i++) {
if(a_eles[i].index != index){
a_eles[i].className = "";
};
};
//滚动页面内容
h3_eles[index].scrollIntoView({
block: 'start',
behavior: 'smooth'
});
//判断是否滚动完毕,再次添加滚动事件
let temp = 0;
setTimeout(function judge(){
let temp1 = document.getElementsByTagName("html")[0].scrollTop;
if (temp != temp1) { //两次滚动高度不等,则认为还没有滚动完毕
setTimeout(judge,100);
temp = temp1; //滚动高度赋值
} else{
document.addEventListener("scroll",autoActive);
temp = null; //放弃引用
}
},100);
};
//绑定动作
document.querySelector("#catalog").addEventListener("click",switchCatalog);
这段代码内容比较多,总结一下:
1. 使用了scrollIntoView()代替锚点定位,并且有滚动效果,通过点击目录列表的index值,寻找页面内容对应相同index值的标题,滚动其到可视口内;
2. 由于滚动会触发之前绑定的scoll事件,从而造成目录闪动,因此需要先取消滚动监听事件(这里就是为啥要事件与处理逻辑相分离,如果不分离,是不能取消的,另外, 由于IE不支持scrollIntoView的滚动效果,所以就没有这个问题,当然如果不设置动画,也不会有此问题);
3. 当页面滚动完毕,需要重新监听滚动事件,否则页面滚动,就没有目录定位效果了。这里就需要判断什么时候滚动结束了,我这里是利用setTimeout定时器链(这样就不用clear定时器了,我比较懒),依然获取父级的scollTop值,并进行缓存,比对两次的值,如果两次值一致了,说明页面停止滚动了,此时就可以加上滚动事件,否则继续判断。
如此两步,利用scrollTop,offsetTop,scrollIntoView,搭配定时器和监听器,就实现了一个双向的定位功能。
嗯,js很强大,就怕不敢想,欢迎大神指正!不胜感激!
目录