【问题标题】:Reset current section counter when user manually scrolls up or down当用户手动向上或向下滚动时重置当前部分计数器
【发布时间】:2019-02-19 05:26:31
【问题描述】:

我正在实现一个按钮,单击该按钮将垂直向下滚动一位团队成员。到目前为止,我已经为一名团队成员实现了一次单击向下滚动,但是当用户手动滚动回到顶部时,代码会中断。

这里正在工作JSFiddle

我的代码

<main class="team container">
    <div v-for='(element, index) in members' :id="element.specialId" class="team__member" v-show="activeIndex === index || widthSmall">
        <div class="team__member__bio">
            <div class="team__member__name">{{element.name}}</div>
        </div>
    </div>
    <a class="scroll-more scroll-team" v-show="widthSmall" @click="move($event)" style="cursor: pointer;">
        <span></span>{{ $t('scroll') }}
    </a>
</main>

export default {
    name: "Team",
    data() {
        return {
            members: [
                {
                    name: "Bojan Dovrtel",
                    specialId: 'bojan-div'
                },
                {
                    name: "Klemen Razinger",
                    specialId: 'kelemen-div'
                },
                {
                    name: "Davor Pečnik",
                    specialId: 'davor-div'
                },
                {
                    name: "Maja Katalinič",
                    specialId: 'maja-div'
                },
                {
                    name: "Petra Vovk",
                    specialId: 'petra-div'
                }
            ],
            secs: document.getElementsByClassName('team__member'),
            currentSection: 0,
        }
    },
    methods: {
        move(e) {
            if (this.currentSection < this.secs.length) {
                if (this.currentSection === 3) {
                    this.widthSmall = false;
                }
                window.scroll({
                    top: this.secs[++this.currentSection].offsetTop,
                    left: 0,
                    behavior: 'smooth'
                });
            } else if (this.currentSection > 0) {
                window.scroll({
                    top: this.secs[--this.currentSection].offsetTop,
                    left: 0,
                    behavior: 'smooth'
                });

            }
        }
    }
};

如何检测用户向上滚动并更改当前部分的值?如果您有任何其他信息,请告诉我,我会提供。谢谢

【问题讨论】:

    标签: javascript vue.js scroll vuejs2


    【解决方案1】:

    您可以遍历元素,找到最接近的元素,其offsetTop (+ offsetHeight) 与当前window.scrollY 滚动时的偏移匹配(或在其范围内),然后决定是否滚动到下一个元素或“重新调整”偏移量:

    new Vue({
      el: '#app',
    
      data() {
        return {
          members: [
            {
              name: "Bojan",
              specialId: 'bojan-div'
            }, 
            {
              name: "Klemen",
              specialId: 'kelemen-div'
            }, 
            {
              name: "Davor",
              specialId: 'davor-div'
            }, 
            {
              name: "Maja",
              specialId: 'maja-div'
            }, 
            {
              name: "Petra",
              specialId: 'petra-div'
            }
          ],
          secs: document.getElementsByClassName('height'),
          currentSection: 0
        }
      },
    
      mounted() {
        this.move();
      },
    
      methods: {
        move() {
          let y = window.scrollY;
          let totalSection = this.secs.length;
          
          for (let index = 0; index < totalSection; index++) {
            let sec = this.secs[index];
    
            if (sec.offsetTop === y) {
              // currentSection matches current window.scrollY, so we want to move to the next section/element
              // Math.min() to ensure it won't go out of range, capping at the length of the total elements.
              this.currentSection = Math.min(index + 1, totalSection - 1);
    
              // Or reset the index once it has scrolled all the way down
              // this.currentSection = (index + 1) % totalSection;
              break;
            }
            else if (sec.offsetTop >= y && y <= (sec.offsetTop + sec.offsetHeight)) {
              // window.scrollY is currently between the matched element's offsetTop and offsetHeight.
              // This is user-initiated scrolling, so let's just "readjust" the offset rather than scrolling to the next element.
              this.currentSection = index;
              break;
            }
          }
    
          window.scroll({
            top: this.secs[this.currentSection].offsetTop,
            left: 0,
            behavior: 'smooth'
          });
        }
      },
    })
    .height {
      background-color: grey;
      height: 300px;
      border: solid 2px black;
    }
    
    .scroll-team {
      position: fixed;
      top: calc(100vh - 6rem);
      left: 50%;
      z-index: 2;
      display: inline-block;
      -webkit-transform: translate(0, -50%);
      transform: translate(0, -50%);
      color: #fff;
      letter-spacing: 0.1em;
      text-decoration: none;
      transition: opacity 0.3s;
    }
    
    .scroll-team a:hover {
      opacity: 0.5;
    }
    
    .scroll-more {
      padding-top: 60px;
      font-size: 1.35rem;
    }
    
    .scroll-more span {
      position: absolute;
      top: 0;
      left: 50%;
      width: 46px;
      height: 46px;
      margin-left: -23px;
      border: 1px solid #fff;
      border-radius: 100%;
      box-sizing: border-box;
      background: rgba(255, 255, 255, 0.2);
    }
    
    .scroll-more span::after {
      position: absolute;
      top: 50%;
      left: 50%;
      content: "";
      width: 16px;
      height: 16px;
      margin: -12px 0 0 -8px;
      border-left: 1px solid #fff;
      border-bottom: 1px solid #fff;
      -webkit-transform: rotate(-45deg);
      transform: rotate(-45deg);
      box-sizing: border-box;
    }
    
    .scroll-more span::before {
      position: absolute;
      top: 0;
      left: 0;
      z-index: -1;
      content: "";
      width: 44px;
      height: 44px;
      box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.1);
      border-radius: 100%;
      opacity: 0;
      -webkit-animation: sdb03 3s infinite;
      animation: sdb03 3s infinite;
      box-sizing: border-box;
    }
    <script src="https://unpkg.com/vue"></script>
    
    <div id="app">
      <div class="height" v-for="(element, index) in members" :key="index">
        {{ element.name }}
      </div>
      <a class="scroll-more scroll-team" @click="move" style="cursor: pointer;">
        <span></span>
      </a>
    </div>

    【讨论】:

      【解决方案2】:

      要检测用户是否滚动,您可以在正在滚动的容器上侦听scroll 事件。在这种情况下,这将是根元素,因此您可以使用 window 添加事件侦听器。

      实现这一目标的一种方法是在createddestroyed 生命周期挂钩中添加和删除scroll 侦听器,如in this answer 所述。

      请注意,当您使用window.scroll({...}) 触发滚动时,也会触发滚动事件,而不仅仅是用户滚动。所以,你需要照顾好它。

      我建议向scroll 事件侦听器添加某种限制,然后通过更改currentSection 值来响应所有scroll 事件,在限制之后。

      例如,您的scroll 事件处理程序可以是:

      ...,
      onScroll(e) {
        if(this.throttle) {
          clearTimeout(this.throttle);
        }
      
        this.throttle = setTimeout(() => (this.currentSection = this.findCurrentSection(e)), 300);
      },
      ...
      

      其中throttle 只是一个用于保存超时值的数据成员。查找currentSection 值的逻辑将仅在最后一个scroll 事件后300 毫秒触发。您也可以使用requestAnimationFrame 来执行此操作,如here 所述。

      findCurrentSection 只是一种基本方法,它遍历secs 数组以根据当前滚动值找到当前部分。

      ...,
      findCurrentSection(e) {
        const curTop = document.documentElement.scrollTop;
        for(let i=0, len=this.secs.length; i < len; ++i) {
          const secTop = this.secs[i].offsetTop;
          if(curTop === secTop) {
              return i;
          } else if(curTop < secTop) {
              return Math.max(i-1, 0);
          }
        }
      },
      ...
      

      请注意,由于在这种特殊情况下滚动容器是根元素,所以我使用的是document.documentElement.scrollTop,但根据上下文,您可以从相应的ScrollEvent(此处为e)中获取所需的值案例)。

      根据您的问题,这是working fiddle。另请注意,我根据引入的更改修改了move函数。

      【讨论】:

      • 试过你的小提琴,如果你在箭头按钮到达底部时继续点击,你会看到它会开始上下滚动而不是.. . 1. 留在底部,或者,2. 以相反的顺序一直向上移动,或者,3. 立即将偏移量重置为第一个元素的。
      • @jom 是的,这是保留原始 move 代码的结果。我实际上是故意留下的。我和小提琴,旨在回答检测滚动何时发生的原始问题。 @Valor_ 可以随心所欲地使用它,并希望对其进行改进以满足他们的要求。
      猜你喜欢
      • 2021-08-22
      • 1970-01-01
      • 1970-01-01
      • 2019-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多