详细讲解js实现电梯导航的实例

 更新时间:2023年10月26日 10:35:15   作者:我的div丢了肿么办  
对于某一个页面内容繁多,如果我们滚动的时间较长,为了增加用户体验,我们需要实现点击某一个按钮,然后滚动到对应的区域,滚动的时候,右侧对应的分类实现高亮,所以本文给大家详细介绍讲解了js实现电梯导航,需要的朋友可以参考下

场景

对于某一个页面内容繁多,

如果我们滚动的时间较长,为了增加用户体验。

我们需要实现点击某一个按钮,然后滚动到对应的区域。

滚动的时候,右侧对应的分类实现高亮

其实,这个功能就2个步骤:

1.点击元素高亮,滚动到对应区域

2.滚动的时候,右侧导航的分类高亮

点击当前元素高亮的实现

1.我们利用事件委托的原理:给被点击子元素的父元素绑定点击事件

2.然后移除 li 元素的激活类

3.给当前被点击的子元素添加上激活类

事件委托也称为事件代理:就是利用事件冒泡,把子元素的事件都绑定到父元素上。

<style>
  :root {
    --h:931px;
  }
  *{
    padding: 0;
    margin: 0;
  }
  .demo1{
    height:var(--h);
    background-color: antiquewhite;
  }
  .demo2{
    height:var(--h);
    background-color: aqua;
  }
  .demo3{
    height:var(--h);
    background-color: blue;
  }
  .demo4{
    height:var(--h);
    background-color:chartreuse;
  }
  .fix-post{
    position: fixed;
    right: 50px;
    bottom: 100px;
    width: 200px;
  }
  li{
    height: 40px;
    line-height: 40px;
    text-align: center;
    list-style: none;
    border-top: 1px solid #fff;
    border-left:  1px solid #fff;
    border-right:  1px solid #fff;
  }
  li:last-child{
    border-bottom: 1px solid #fff;
  }
  .liactive{
    background-color: cornsilk;
  }
</style>

<body>
  <div>
    <div class="demo1">1</div>
    <div class="demo2">2</div>
    <div class="demo3">3</div>
    <div class="demo4">4</div>
  </div>
  <ul class="fix-post" id="nav">
    <li class="liactive">1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
</body>
<script>
  let domNav= document.getElementById('nav')
  let liList=document.querySelectorAll("#nav li")
  console.log('liList', liList)
  // 给父级元素注册点击事件(利用事件委托)
  domNav.addEventListener('click',(event)=>{
    for(let i=0;i<liList.length;i++){
      // 移除所有元素的类名liactive
      liList[i].classList.remove('liactive')
    }
    console.log('event.target', event.target)
    // 给当前元素添加激活这个类名
    event.target.classList.add('liactive'); 
  })
</script>

点击右侧按钮,滚动到对应区域

1.给右侧的按钮添加上索引。

2.点击索引的时候 * 每个区域的高度

3.使用window.scrollTo({ })进行滚动

<script>
  let domNav= document.getElementById('nav')
  let liList=document.querySelectorAll("#nav li")
  console.log('liList', liList)
  // 给父级元素注册点击事件(利用事件委托)
  domNav.addEventListener('click',(event)=>{
    for(let i=0;i<liList.length;i++){
      // 移除所有元素的类名liactive
      liList[i].classList.remove('liactive')
      // 给右侧的按钮添加上索引
      liList[i]['index']=i
    }
    console.log('event.target', event.target.index)
    // 给当前元素添加激活这个类名
    event.target.classList.add('liactive'); 

    // 点击按钮的时候,滚动到相应的区域
    window.scrollTo({
      top:event.target.index * 931,
      behavior:"smooth" // 平滑的滚动
    })
  })
</script>

滑动到对应区域右侧按钮自动高亮

// 实现滚动的时候,右侧区域自动高亮
window.addEventListener('scroll',()=>{
  // 兼容
  let top = document.documentElement.scrollTop || document.body.scrollTop
  // 获取当前区域的下标
  let index = Math.floor(top/931)
  console.log('top,index',top,index)
  for(let i=0;i<liList.length;i++){
    // 移除所有元素的类名liactive
    liList[i].classList.remove('liactive')
  }
  // 给当前元素添加激活这个类名
  liList[index].classList.add('liactive');
},false)

发现2个问题

问题1:

出现这个问题的原因是:距离顶部的高度仅仅超过第一层区域的一点,
这个时候页面显示绝大部分区域是第二层的,
但是右侧按钮显示的是当前是第1层。
怎么解决这个问题?我们给当前区域手动新增一个高度。
这个高度一般为 3/10

问题2:

我们每次滚动的时候,都在移除元素激活类,然后新增。
这样不太好,没有必须要。
我们需要判断一下

优化代码[每次滚动的时候都在移除元素的激活类]

// 实现滚动的时候,右侧区域自动高亮
let index=0
window.addEventListener('scroll',()=>{
  console.log(222)
  // 兼容
  let top = (document.documentElement.scrollTop || document.body.scrollTop) + 279 //手动新增一个值
  // 如果索引不变,则不取新增或者移除类名
  if( Math.floor(top/931) != index){
    // 获取当前区域的下标
    let index = Math.floor(top/931)
    for(let i=0;i<liList.length;i++){
      // 移除所有元素的类名liactive
      liList[i].classList.remove('liactive')
    }
    // 给当前元素添加激活这个类名
    liList[index].classList.add('liactive');
  }
},false)

scroll 事件不滚动也会触发

我们每次刷新页面的时候,滚动事件都会被触发。

因为:刷新的时候可视区域距离顶部有距离。所以滚动事件会被触发;【现象】

这样就会导致初始化(可视区域距离顶部有距离)刷新页面的时候。

右侧的指示灯会切换2次(第一次html上写激活类,第二次是由于有距离触发了滚动事件)。

这样不太好。我们需要优化一下:

删除html上的激活类。如果距离为0

处理右侧的指示灯在距离顶部有距离的时候,快速切换了2次

let index
let topValue = document.documentElement.scrollTop || document.body.scrollTop
// 距离为0.显示第一个指示灯
if(topValue==0){
  liList[0].classList.add('liactive');
}

scroll 事件特别说明

在 iOS UIWebViews 中,
滚动进行时不会触发 scroll 事件;
只有当滚动结束后事件才会被触发。
参见 Bootstrap issue #16202。Safari 和 WKWebViews 则没有这个问题。
ps:刷新的时候可视区域距离顶部有距离。滚动事件也会被触发;不一定滚动才会触发

每个区域固定高度实现导航【全部代码】

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    :root {
      --h:931px;
    }
    *{
      padding: 0;
      margin: 0;
    }
    .demo1{
      height:var(--h);
      background-color: antiquewhite;
    }
    .demo2{
      height:var(--h);
      background-color: aqua;
    }
    .demo3{
      height:var(--h);
      background-color: blue;
    }
    .demo4{
      height:var(--h);
      background-color:chartreuse;
    }
    .fix-post{
      position: fixed;
      right: 50px;
      bottom: 100px;
      width: 200px;
    }
    li{
      height: 40px;
      line-height: 40px;
      text-align: center;
      list-style: none;
      border-top: 1px solid #fff;
      border-left:  1px solid #fff;
      border-right:  1px solid #fff;
    }
    li:last-child{
      border-bottom: 1px solid #fff;
    }
    .liactive{
      background-color: cornsilk;
    }
  </style>
</head>
<body>
  <div>
    <div class="demo1">1111</div>
    <div class="demo2">2</div>
    <div class="demo3">3</div>
    <div class="demo4">4</div>
  </div>
  <ul class="fix-post" id="nav">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
</body>
<script>
  let domNav= document.getElementById('nav')
  let liList=document.querySelectorAll("#nav li")
  console.log('liList', liList)
  // 给父级元素注册点击事件(利用事件委托)
  domNav.addEventListener('click',(event)=>{
    for(let i=0;i<liList.length;i++){
      // 移除所有元素的类名liactive
      liList[i].classList.remove('liactive')
      // 给右侧的按钮添加上索引
      liList[i]['index']=i
    }
    console.log('event.target', event.target.index)
    // 给当前元素添加激活这个类名
    event.target.classList.add('liactive'); 

    // 点击按钮的时候,滚动到相应的区域
    window.scrollTo({
      top:event.target.index * 931,
      behavior:"smooth" // 平滑的滚动
    })
  })
 
  let index
  let topValue = document.documentElement.scrollTop || document.body.scrollTop
  // 离为0.显示第一个指示灯
  if(topValue==0){
    liList[0].classList.add('liactive');
  }
  // 实现滚动的时候,右侧区域自动高亮
  window.addEventListener('scroll',()=>{
    console.log('scroll-触发')
    // 兼容
    let top = (document.documentElement.scrollTop || document.body.scrollTop) + 279 //手动新增一个值
    // 如果索引不变,则不取新增或者移除类名
    if( Math.floor(top/931) != index){
      // 获取当前区域的下标
      index = Math.floor(top/931)
      for(let i=0;i<liList.length;i++){
        // 移除所有元素的类名liactive
        liList[i].classList.remove('liactive')
      }
      // 给当前元素添加激活这个类名
      liList[index].classList.add('liactive');
    }
  },false)
</script>
</html>

每个区域高度不一致怎么滚动到对应的区域

虽然我们的滚动可以正确显示右侧的高亮。
点击右侧区域也可以显示到对应的区域。
但是我们每个区域的高度是一致的。
在有些情况,每个区域的高度不一致,
怎么滚动到对应的区域,这个问题怎么处理呢?
我们可以判断当前区域在哪个区间。

<body>
  <div id="cont">
    <div class="demo1">1111</div>
    <div class="demo2">2</div>
    <div class="demo3">3</div>
    <div class="demo4">4</div>
  </div>
  <ul class="fix-post" id="nav">
    <li id="demo1">1</li>
    <li id="demo2">2</li>
    <li id="demo3">3</li>
    <li id="demo4">4</li>
  </ul>
</body>
<script>
  let contDivList= document.querySelectorAll('#cont div')
  let liList=document.querySelectorAll("#nav li")
  liList.forEach(link =>{
    // 给每个元素注册点击事件
    link.addEventListener('click',(event)=>{
      // 获取被点击元素的类名
      let currentClickElement= event.target.getAttribute('id')
      // 获取对应的区域元素dom
      let currentTargetTop= document.querySelector('.' + currentClickElement)
      // 获取当前这个点击元素的距离顶部的距离
      let eleTop=  currentTargetTop.offsetTop
       // 点击按钮的时候,滚动到相应的区域
      window.scrollTo({
        top:eleTop,
        behavior:"smooth" // 平滑的滚动
      })
    })
  })
  // 实现滚动的时候,右侧区域自动高亮
  window.addEventListener('scroll',()=>{
    let top = window.scrollTop || document.documentElement.scrollTop || document.body.scrollTop;
    console.log('top', top)
    contDivList.forEach(element => {
      // 获取每个元素距离顶部的距离
      const offsetTop = element.offsetTop;
      // 获取每个元素的高度
      const offsetHeight = element.offsetHeight;
      // 判断当前内容区块是否在可视范围内
      if (top >= offsetTop && top < offsetTop + offsetHeight) {
        liList.forEach(function (link) {
          if (link.getAttribute('id') === element.getAttribute('class')) {
            link.classList.add('liactive');
          } else {
            link.classList.remove('liactive');
          }
        });
      }
    });
  },false)
</script>

咋们这种判断方式有没有问题?

有的。

const offsetTop = element.offsetTop;
console.log('offsetTop', offsetTop)
// 获取每个元素的高度
const offsetHeight = element.offsetHeight;
// 判断当前内容区块是否在可视范围内
if (top >= offsetTop && top < offsetTop + offsetHeight) {
  
}

这个判断是不准确的。容易出问题。
比如说:某一个区域的高度大于屏幕的可用区域并且下一个区域小于上一个区域的高度。
就可能出现问题。
下一楼层无法正确高亮(在滚动的时候)区域与高亮区域不匹配

全部代码:每个区域高度不确定导航

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    :root {
      --h:931px;
    }
    *{
      padding: 0;
      margin: 0;
    }
    .demo1{
      height: 800px;
      background-color: antiquewhite;
    }
    .demo2{
      height: 450px;
      background-color: aqua;
    }
    .demo3{
      height: 1200px;
      background-color: blue;
    }
    .demo4{
      height: 660px;
      background-color:chartreuse;
    }
    .demo5{
      height: 1000px;
      background-color:rgb(33, 58, 7);
    }
    .fix-post{
      position: fixed;
      right: 50px;
      bottom: 100px;
      width: 200px;
    }
    li{
      height: 40px;
      line-height: 40px;
      text-align: center;
      list-style: none;
      border-top: 1px solid #fff;
      border-left:  1px solid #fff;
      border-right:  1px solid #fff;
    }
    li:last-child{
      border-bottom: 1px solid #fff;
    }
    .liactive{
      background-color: cornsilk;
    }
  </style>
</head>
<body>
  <div id="cont">
    <div class="demo1">1111</div>
    <div class="demo2">2</div>
    <div class="demo3">3</div>
    <div class="demo4">4</div>
    <div class="demo5">5</div>
  </div>
  <ul class="fix-post" id="nav">
    <li id="demo1">1</li>
    <li id="demo2">2</li>
    <li id="demo3">3</li>
    <li id="demo4">4</li>
    <li id="demo5">5</li>
  </ul>
</body>
<script>
  let contDivList= document.querySelectorAll('#cont div')
  let liList=document.querySelectorAll("#nav li")
  liList.forEach(link =>{
    // 给每个元素注册点击事件
    link.addEventListener('click',(event)=>{
      // 获取被点击元素的类名
      let currentClickElement= event.target.getAttribute('id')
      // 获取对应的区域元素dom
      let currentTargetTop= document.querySelector('.' + currentClickElement)
      // 获取当前这个点击元素的距离顶部的距离
      let eleTop=  currentTargetTop.offsetTop
       // 点击按钮的时候,滚动到相应的区域
      window.scrollTo({
        top:eleTop,
        behavior:"smooth" // 平滑的滚动
      })
    })
  })

  // 实现滚动的时候,右侧区域自动高亮
  window.addEventListener('scroll',()=>{
    let top = window.scrollTop || document.documentElement.scrollTop || document.body.scrollTop;
    console.log('top', top)
    contDivList.forEach(element => {
      // 获取每个元素距离顶部的距离
      const offsetTop = element.offsetTop;
      console.log('offsetTop', offsetTop)
      // 获取每个元素的高度
      const offsetHeight = element.offsetHeight;
      // 判断当前内容区块是否在可视范围内
      if (top >= offsetTop && top < offsetTop + offsetHeight) {
        liList.forEach(function (link) {
          if (link.getAttribute('id') === element.getAttribute('class')) {
            link.classList.add('liactive');
          } else {
            link.classList.remove('liactive');
          }
        });
      }
    });
  },false)
</script>
</html>

以上就是详细讲解js实现电梯导航的实例的详细内容,更多关于js实现电梯导航的资料请关注脚本之家其它相关文章!

相关文章

  • uni-app app引入天地图简单代码示例

    uni-app app引入天地图简单代码示例

    uni-app是一种基于Vue.js的跨平台开发框架,允许开发者使用统一的代码编写多端应用,这篇文章主要给大家介绍了关于uni-app app引入天地图的相关资料,需要的朋友可以参考下
    2024-02-02
  • P3P Header解决Cookie跨域的问题

    P3P Header解决Cookie跨域的问题

    P3P Header解决Cookie跨域的问题,需要的朋友可以参考一下
    2013-03-03
  • JS面向对象实现飞机大战

    JS面向对象实现飞机大战

    这篇文章主要为大家详细介绍了JS面向对象实现飞机大战,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-08-08
  • JavaScript中ES6规范中let和const的用法和区别

    JavaScript中ES6规范中let和const的用法和区别

    这篇文章主要介绍了JavaScript中ES6规范中let和const的用法和区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • JS实现拖动滚动条评分的效果代码分享

    JS实现拖动滚动条评分的效果代码分享

    本文给大家基于js实现拖动滚动条评分效果,在项目开发中经常可以用到的,大家可以更加需要适当的添加修改,对js评分效果感兴趣的朋友一起看看吧
    2016-09-09
  • Object.defineproperty方法示例详解

    Object.defineproperty方法示例详解

    Object.defineproperty 的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性,这篇文章主要介绍了Object.defineproperty方法,需要的朋友可以参考下
    2022-12-12
  • JavaScript+Canvas实现绘制音频可视化波形图

    JavaScript+Canvas实现绘制音频可视化波形图

    这篇文章主要为大家详细介绍了如何利用JavaScript和Canvas实现绘制音频可视化波形图,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-02-02
  • 微信小程序导入Vant报错VM292:1 thirdScriptError的解决方法

    微信小程序导入Vant报错VM292:1 thirdScriptError的解决方法

    这篇文章主要给大家介绍了关于微信小程序导入Vant报错VM292:1 thirdScriptError的解决方法,文中通过示例代码介绍的非常详细,对大家学习或者使用微信小程序具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-08-08
  • javascript的indexOf忽略大小写的方法

    javascript的indexOf忽略大小写的方法

    javascript 中 indexOf 是严格区分大小写的 如何才能忽略大小写呢?
    2008-08-08
  • Javascript ParentNode和ChildNode接口原理解析

    Javascript ParentNode和ChildNode接口原理解析

    这篇文章主要介绍了Javascript ParentNode和ChildNode接口原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03

最新评论