美文网首页
Vue导航栏吸顶切换功能实现

Vue导航栏吸顶切换功能实现

作者: 小小鱼yyds | 来源:发表于2020-11-27 14:29 被阅读0次

      Vue导航栏吸顶切换功能实现,兼容px2rem-loader自动转rem
    最上面的ad-show在实际项目中可以用来做商品或者广告轮播,下面
    设置了三个区域块,分别为onePage,twoPage和threePage,在实际项目中可以用作商品详情,物流说明,注意事项等。
      在阅读代码之前,感兴趣的童鞋可以先了解一下clientHeight、offsetHeight、scrollHeight、offsetTop、scrollTop的区别。这样才能明白代码的计算方式和获取元素节点高度的方式。
      附上他人博客链接,写的不错,可以提前阅读一下帮助理解此篇内容:https://blog.csdn.net/qq_35430000/article/details/80277587
       如果木有时间阅读,木有关系,我大概总结了一下:

    • 网页可见区域高:document.body.clientHeight
    • 网页正文全文高:document.body.scrollHeight
    • 网页可见区域高(包括边线的高):document.body.offsetHeight
    • 网页被卷去的高:document.body.scrollTop
    • 屏幕分辨率高:window.screen.height
    • 节点高度(包含padding和border):this.$refs.scrollTwo.offsetTop
    • 节点高度(包含padding,但不包含border):this.$refs.scrollTwo.clientHeight
      严谨起见,我采用了offsetTop来获取节点自己的高度
      因为高度都是动态获取的元素高度,所以不必担心项目用了px2rem-loader把px都自动转成了rem


      微信图片_20201127143453.jpg
    <template>
      <div id="needscroll" class="hello">
        <div class="ad-show">
          <p>展示图</p>
        </div>
        <div class="onePage" ref="scrollOne">区域一</div>
        <div class="twoPage" ref="scrollTwo">区域二</div>
        <div class="threePage" ref="scrollThree">区域三</div>
        <div class="home-menu" ref="menuHome" v-if="showMenu">
          <p :class="{ active: active === 1 }" @click="changeActive(1)">区域一</p>
          <p :class="{ active: active === 2 }" @click="changeActive(2)">区域二</p>
          <p :class="{ active: active === 3 }" @click="changeActive(3)">区域三</p>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: "HelloWorld",
      data() {
        return {
          active: 1,
          rememberScroll: 0,
          showMenu: false,
          scroll1: 0,
          scroll2: 0,
          scroll3: 0,
          isScroll: false,
          menuHeight: 0,
        };
      },
      methods: {
        getScroll() {
          let scrollTop =
            window.pageYOffset ||
            document.documentElement.scrollTop ||
            document.body.scrollTop;
          let scrollT1 = this.$refs.scrollOne.offsetTop;
          this.scroll1 = scrollT1;
          let scrollT2 = this.$refs.scrollTwo.offsetTop;
          this.scroll2 = scrollT2;
          let scrollT3 = this.$refs.scrollThree.offsetTop;
          this.scroll3 = scrollT3;
          //这里之所以加了一层判断,是因为menuHome刚开始为隐藏状态,$refs获取为undefined
          if (this.$refs.menuHome) {
            let space = this.$refs.menuHome.scrollHeight;
            if (scrollTop >= scrollT1 - space - 10) {
              this.showMenu = true;
            } else {
              this.showMenu = false;
            }
          } else {
            if (scrollTop >= scrollT1 - 60) {
              this.showMenu = true;
            } else {
              this.showMenu = false;
            }
          }
        },
        changeActive(val) {
          this.isScroll = true;
          this.active = val;
          let scrolly = 0;
          let space = this.$refs.menuHome.scrollHeight;
          if (val === 1) {
            scrolly = this.scroll1 - space;
          } else if (val === 2) {
            scrolly = this.scroll2 - space;
          } else {
            scrolly = this.scroll3 - space;
          }
          //这里之所以不用这个方法,是因为真机没有动画效果,但在PC浏览器是有的
          // window.scrollTo({
          //   top: scrolly,
          //   behavior: "smooth",
          // });
          this.smoothScroll(0, scrolly, 500);
        },
        smoothScroll(endX, endY, duration) {
          let startX = window.scrollX || window.pageXOffset,
            startY = window.scrollY || window.pageYOffset,
            distanceX = endX - startX,
            distanceY = endY - startY,
            startTime = new Date().getTime();
    
          // Easing function
          let easeInOutQuart = function (time, from, distance, duration) {
            if ((time /= duration / 2) < 1)
              return (distance / 2) * time * time * time * time + from;
            return (-distance / 2) * ((time -= 2) * time * time * time - 2) + from;
          };
    
          let timer = window.setInterval(function () {
            let time = new Date().getTime() - startTime,
              newX = easeInOutQuart(time, startX, distanceX, duration),
              newY = easeInOutQuart(time, startY, distanceY, duration);
            if (time >= duration) {
              window.clearInterval(timer);
            }
            window.scrollTo(newX, newY);
          }, 1000 / 60); // 60 fps
        },
      },
      mounted() {
        window.addEventListener("scroll", this.getScroll);
      },
      destroyed(){
          //不要忘记移除掉监听,否则跳转到其他页面会报错的
        window.removeEventListener('scroll',this.getScroll)
      }
    };
    </script>
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped lang="scss">
    .hello {
      .ad-show {
        width: 100%;
        height: 200px;
        display: flex;
        justify-content: center;
        align-items: center;
        background: crimson;
      }
      .onePage {
        width: 100%;
        height: 500px;
        text-align: center;
        background: palegoldenrod;
      }
      .twoPage {
        width: 100%;
        height: 400px;
        text-align: center;
        background: powderblue;
      }
      .threePage {
        width: 100%;
        height: 400px;
        text-align: center;
        background: peachpuff;
      }
      .home-menu {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        height: 50px;
        background: white;
        z-index: 999;
        display: flex;
        flex-direction: row;
        p {
          flex: 1;
          height: 50px;
          text-align: center;
          line-height: 50px;
          font-size: 14px;
        }
      }
      .active {
        color: lightsalmon;
        background: rgb(247, 247, 247);
      }
    }
    

    我本来想实现滑动到每个区域时,导航栏会自动选择某个区域,但是在scroll的监听方法里面写,快速点击时会产生交叠问题,此功能还会后续优化,有好想法的童鞋欢迎提出你的宝贵意见,以帮助我更好的完善这个功能

    相关文章

      网友评论

          本文标题:Vue导航栏吸顶切换功能实现

          本文链接:https://www.haomeiwen.com/subject/dxsxwktx.html