js控制鼠标滚轮移动距离

  • 需求分析
  • 效果
  • 实现思路
  • 技术点/知识点
  • 踩坑记录
  • 示例代码



该种实现方式不同于轮播等css控制,可以直接嵌入到web页面,不会破坏页面结构,即拿即用。

需求分析

web端页面如果采用长页面模式,参考特斯拉官网,对于在同一页面需要展示很多图片内容的网站来说,通常浏览器默认的滚动条一次滚动的距离,对于用户体验很不友好,同时对于页面完整性的展示效果也有影响,比如
三星官网 这种长页面,用户需要频繁使用滚轮。
参考特斯拉官网之后,使用js实现了使用鼠标滚轮,控制滚动条的滚动距离,让用户在一次滚轮滚动中,可以看到一个完整的页面。

效果

对比

正常滚动

滚动控制

js控制Element滚动条滚动指定位置 js控制页面滚动_html

js控制Element滚动条滚动指定位置 js控制页面滚动_js_02

实现思路

首先明确,我们的页面中有多少需要滚动定位的元素,比如有这样一个列表[ele1,ele2,ele3],当用户滚动滚轮时,需要暂时让滚轮事件停止响应,因为滚轮事件的触发条件是滚轮里的卡点(滚动时明显的停顿感)每动一下就要触发,所以一次触发后需要先停止一会(防止反复触发),并且,在触发后,如果由代码实现滚动,还需要阻止用户滚轮的默认行为,否则两种滚动方式都会运行,页面会卡住不动。
明确滚轮事件的原理之后,需要确认是向上滚动还是向下,一次滚动的距离是多少。根据滚轮事件,向上向下很好判断。滚动距离需要根据实际情况,比如,我们在页面中抓了3个点,获取这3个点距离文档顶部的距离就可以了,之后实现页面滚动的函数,让页面滚动到我们希望的位置。

技术点/知识点

需要了解一下技术点:

  1. preventDefault ,阻止浏览器默认事件;
  2. window.scrollTo 页面进行滚动;
  3. mousewheel 鼠标滚轮触发事件;
  4. document.querySelector 选取页面元素;
  5. 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>