js控制鼠标滚轮移动距离
- 需求分析
- 效果
- 实现思路
- 技术点/知识点
- 踩坑记录
- 示例代码
该种实现方式不同于轮播等css控制,可以直接嵌入到web页面,不会破坏页面结构,即拿即用。
需求分析
web端页面如果采用长页面模式,参考特斯拉官网,对于在同一页面需要展示很多图片内容的网站来说,通常浏览器默认的滚动条一次滚动的距离,对于用户体验很不友好,同时对于页面完整性的展示效果也有影响,比如
三星官网 这种长页面,用户需要频繁使用滚轮。
参考特斯拉官网之后,使用js实现了使用鼠标滚轮,控制滚动条的滚动距离,让用户在一次滚轮滚动中,可以看到一个完整的页面。
效果
对比
正常滚动 | 滚动控制 |
实现思路
首先明确,我们的页面中有多少需要滚动定位的元素,比如有这样一个列表[ele1,ele2,ele3],当用户滚动滚轮时,需要暂时让滚轮事件停止响应,因为滚轮事件的触发条件是滚轮里的卡点(滚动时明显的停顿感)每动一下就要触发,所以一次触发后需要先停止一会(防止反复触发),并且,在触发后,如果由代码实现滚动,还需要阻止用户滚轮的默认行为,否则两种滚动方式都会运行,页面会卡住不动。
明确滚轮事件的原理之后,需要确认是向上滚动还是向下,一次滚动的距离是多少。根据滚轮事件,向上向下很好判断。滚动距离需要根据实际情况,比如,我们在页面中抓了3个点,获取这3个点距离文档顶部的距离就可以了,之后实现页面滚动的函数,让页面滚动到我们希望的位置。
技术点/知识点
需要了解一下技术点:
- preventDefault ,阻止浏览器默认事件;
- window.scrollTo 页面进行滚动;
- mousewheel 鼠标滚轮触发事件;
- document.querySelector 选取页面元素;
- element.offsetTop 当前元素距离文档顶部距离;
了解了这几点,就能实现我们的需求了。
在代码中,
有2个关键的变量,一个是cur_index,描述当前滚动到哪个元素。
invoke,描述当前是否在滚动中,在moveTo函数中,先判断该变量,避免重复触发。
踩坑记录
最开始期望使用scroll事件,控制浏览器的滚动条。实际编写时发现,监听scroll事件时,改变高度是无效的。
原因是scroll事件监听的是,任何改变文档位置的触发的函数或者用户触发的动作,所以当监听用户动作时,改变文档高度是不可行的,这会循环触发scroll事件,导致页面不停触发scroll,不能实现该功能。
而mousewheel事件只监听滚轮,所以最终实现了该功能。
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<style>
.a,.b,.c{
width: 100%;
height: 100vh;
background:red;
}
.b{
background: blue;
}
.other{
width: 100%;
height: 30vh;
background:black;
}
.other_1{
background:white;
}
.other_2{
background:black;
}
.other_3{
background:white;
}
</style>
<body>
<div class="other other_0"></div>
<div class="other other_1"></div>
<div class="other other_2"></div>
<div class="other other_3"></div>
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<script>
window.addEventListener("mousewheel",WheelGo)
var cur_index = -1
var invoke = false
list = [{ele:"other_0"},{ele:"other_1"},{ele:"other_2"},{ele:"other_3"},{ ele: "a" }, { ele: "b" }, { ele: "c" }]
list = initSrollPosition("body",list)
function initSrollPosition(ele,list){
var container = document.querySelector(ele)
for(var i in list){
list[i].position = document.querySelector("."+list[i].ele).offsetTop
}
return list
}
//window.addEventListener("mousewheel",go)
//
// window.addEventListener("scroll",judge)
// function judge(e){
// console.log(e)
// var scrollPosition = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
// var first_position = list[0].position/2
// console.log(scrollPosition)
// if(scrollPosition>=first_position){
// }
// }
// function loseWheelControl(){
// window.removeEventListener("mousewheel",go)
// console.log("loseWheelControl")
// }
function stopDefault(e){
e.preventDefault()
return false
}
function WheelGo(e){
//判断当前所处位置
var isDown = e.deltaY>0?true:false
stopDefault(e)
if(invoke){
return
}
moveTo(isDown)
}
function moveTo(isDown){
var cur_state
if(isDown){
cur_index = cur_index>=list.length-1?list.length-1:cur_index+1
var cur_state = list[cur_index]
}else{
cur_index = cur_index<=0?0:cur_index-1
cur_state = list[cur_index]
}
console.log("invoke")
invoke = true
window.scrollTo({top:(cur_state.position),left:0,behavior:"smooth"})
setTimeout(()=>{
invoke = false
},500)
}
</script>
</body>
</html>