zoukankan      html  css  js  c++  java
  • vue-防京东详情导航跟随滚动

    前段时间 项目要求做类似京东详情导航。今日有空记录哈!

     坑:window.scrollTo({top: 0, behavior: "smooth" }); 不知为何无法生效

    解决:dom取包含总体内容的元素。次例子取 let el = this.$refs.wrapper;

    大致样式:gif上看着导航的高亮状态闪的很快,实际上并不如此。新手新手不会操作

     大致思路:

    step1:先实现导航点击切换到响应锚点
    step2:添加页面滚动事件,(注意离开当前页面时要销毁滚动事件,以免切换路由时影响其他路由。。。。

    完整代码:

    <!--
     * @Author: lingxie
     * @Date: 2020-05-27 14:35:35
     * @Descripttion: 
    --> 
    <template>
      <div class="model-box">
        <div class="nav-wrap" v-if="isShowNav" ref="navWrap">
          <nav>
            <ul>
              <li v-for="(i,idx) in navList" :key="'nav'+idx">
                <span :class="{'active':curNavIdx==idx}" @click="handleNav(idx)">{{i}}</span>
              </li>
            </ul>
          </nav>
        </div>
        <div class="con" ref="wrapper" id="wrapper">
          <section ref="panel0">
            <h3>商品</h3>
            <p v-for="(i,idx) in 20" :key="'0'+idx">商品</p>
          </section>
    
          <section ref="panel1">
            <h3>评价</h3>
            <p v-for="(i,idx) in 20" :key="'0'+idx">评价</p>
          </section>
    
          <section ref="panel2">
            <h3>详情</h3>
            <p v-for="(i,idx) in 10" :key="'0'+idx">详情</p>
          </section>
    
          <section ref="panel3">
            <h3>推荐</h3>
            <p v-for="(i,idx) in 20" :key="'0'+idx">推荐</p>
          </section>
        </div>
      </div>
    </template>
    <script>
    export default {
      data() {
        return {
          isShowNav: false, //是否展示导航
          scrollTop: 0,
          curNavIdx: 0,
          navList: ["商品", "评价", "详情", "推荐"]
        };
      },
      watch:{
        curNavIdx(val){
          console.log('索引',val);
          this.curNavIdx = val;
        }
      },
      mounted() {
        this.$nextTick(() => {
          window.addEventListener("scroll", this.handleScroll, true);
        });
      },
      beforeDestroy() {
        window.removeEventListener("scroll", this.handleScroll, true);
      },
      methods: {
        // 点击跳转至相应锚点
        handleNav(idx) {
          this.curNavIdx = idx;
          let el = this.$refs.wrapper;
          let navHeight = this.$refs.navWrap.offsetHeight;
          let panel1T = this.$refs.panel1.offsetTop - navHeight;
          let panel2T = this.$refs.panel2.offsetTop - navHeight;
          let panel3T = this.$refs.panel3.offsetTop - navHeight;
            console.log(panel1T,panel2T,panel3T);
            if( this.curNavIdx==0){
              console.log('进入',0);
              el.scrollTo({top: 0, behavior: "smooth" });
            }
            if( this.curNavIdx==1){
              console.log('进入',1);
              el.scrollTo({top: panel1T, behavior: "smooth" });
            }
            if( this.curNavIdx==2){
               console.log('进入',2);
               el.scrollTo({top: panel2T, behavior: "smooth" });
            }
            if( this.curNavIdx==3){
               console.log('进入',3);
                el.scrollTo({top: panel3T, behavior: "smooth" });
            }
        },
        handleScroll() {
          var el = this.$refs.wrapper;
          let scrollTop = el.scrollTop; // 获取当前的滚动距离
          let clientHeight = el.clientHeight; //获取当前可视区域
          let scrollHeight = el.scrollHeight; //获取当前滚动高度
          // console.log(scrollTop);
          if (scrollTop > 30) {
            this.isShowNav = true;
          } else {
            this.isShowNav = false;
          }
          if (this.isShowNav) {
            // console.log(scrollTop,clientHeight,scrollHeight,';;;;;;;;;;;;;;');
            // 判断是否滚动到底部
            let isBottom = false;
            if (clientHeight + scrollTop === scrollHeight) {
              isBottom = true;
              console.log("滚动到底步了");
            }
            var navE = this.$refs.navWrap;
            if (navE) {
              var navHeight = navE.offsetHeight;
            }
            let panel1T = this.$refs.panel1.offsetTop - navHeight;
            let panel2T = this.$refs.panel2.offsetTop - navHeight;
            let panel3T = this.$refs.panel3.offsetTop - navHeight;
            // console.log(panel1T,panel2T,panel3T,'推荐高度',panelH);
            if (scrollTop < panel1T) {
              if (this.curNavIdx != 0) {
                this.curNavIdx = 0;
              }
            }
            if (scrollTop >= panel1T && scrollTop < panel2T) {
              if (this.curNavIdx != 1) {
                this.curNavIdx = 1;
              }
            }
            if (scrollTop >= panel2T && scrollTop < panel3T) {
              if (this.curNavIdx != 2) {
                this.curNavIdx = 2;
              }
            }
            if (scrollTop >= panel3T || isBottom) {
              if (this.curNavIdx != 3) {
                this.curNavIdx = 3;
              }
            }
          }
        }
      }
    };
    </script>
    <style lang="less" scoped>
    *{
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    li{
      list-style: none;
    }
    .model-box {
      height: 100%;
      .paddingT{
        padding-top: 60px;
      }
      .con {
        // background: #f8f8f8;
        position: relative;
        height: 100%;
        overflow-y: scroll;
        &.paddingT{
          top: 60px;
        }
      }
    }
    .nav-wrap {
      position: fixed;
      left: 50%;
      top: 0;
       100%;
      transform: translateX(-50%);
      z-index: 99;
      background: lightblue;
      nav {
        height: 40px;
      }
      ul {
        display: flex;
        height: 100%;
        li {
          flex: 1;
          padding-top: 10px;
          text-align: center;
          position: relative;
          span {
            position: absolute;
            left: 50%;
            transform: translateX(-50%);
            font-size: 14px;
            color: #000;
            &::after {
              display: block;
              position: absolute;
              left: 50%;
              transform: translateX(-50%);
              bottom: -10px;
               40px;
              height: 3px;
              content: "";
            }
            &.active {
              &::after {
                background-image: linear-gradient(
                  to right,
                  rgb(21, 255, 165) 27%,
                  rgb(21, 255, 165) 47%,
                  rgb(105, 255, 197) 60%,
                  rgb(189, 255, 229) 100%
                );
              }
            }
          }
        }
      }
    }
    section {
      margin-bottom: 40px;
    }
    </style>

    优化滚动事件:

        handleScroll() {
          let el = this.$refs.wrapper;
          let scrollTop = el.scrollTop; // 获取当前的滚动距离
          let clientHeight = el.clientHeight; //获取当前可视区域
          let scrollHeight = el.scrollHeight; //获取当前滚动高度
          // console.log(scrollTop);
          if (scrollTop > 30) {
            this.isShowNav = true;
          } else {
            this.isShowNav = false;
          }
          if (this.isShowNav) {
            // console.log(scrollTop,clientHeight,scrollHeight,';;;;;;;;;;;;;;');
            // 判断是否滚动到底部
            let isBottom = false;
            if (clientHeight + scrollTop === scrollHeight) {
              isBottom = true;
              console.log("滚动到底步了");
            }
            var navE = this.$refs.navWrap;
            if (navE) {
              var navHeight = navE.offsetHeight;
            }
            let panel1T = this.$refs.panel1.offsetTop - navHeight;
            let panel2T = this.$refs.panel2.offsetTop - navHeight;
            let panel3T = this.$refs.panel3.offsetTop - navHeight;
            const offsetTopArr = []
            offsetTopArr.push(0,panel1T,panel2T,panel3T)
            let navIndex = 0
            for (let n = 0; n < offsetTopArr.length; n++) {
              // 若到底了,则当前索引为3
              // 否则导航索引就应该是 n 了
              if (scrollTop >= offsetTopArr[n]) {
                 if(!isBottom){
                   navIndex = n;
                 }else{
                   navIndex = 3;
                 }
              }
            }
            this.curNavIdx = navIndex
          }
        }
  • 相关阅读:
    java并发AtomicIntegerArray
    java并发:原子类之AtomicLong
    java并发:初探消费者和生产者模式
    java并发:初探用户线程和守护线程
    java并发:interrupt进程终止
    java并发:join源码分析
    java并发:初探sleep方法
    java并发(二):初探syncronized
    java并发(一):初探线程的创建
    Git 操作
  • 原文地址:https://www.cnblogs.com/lingXie/p/12988642.html
Copyright © 2011-2022 走看看