Сброс счетчика текущей секции, когда пользователь вручную прокручивает вверх или вниз - PullRequest
0 голосов
/ 19 февраля 2019

Я реализую кнопку, которая при нажатии будет вертикально прокручиваться вниз для одного члена команды.До сих пор мне удавалось, что один клик прокручивается вниз для одного члена команды, но код прерывается, когда пользователь вручную прокручивает вверх.

Здесь работает JSFiddle

Myкод

<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'
                });

            }
        }
    }
};

Как я могу обнаружить, что пользователи прокрутили вверх и изменить значение текущего раздела?Если у вас есть какая-либо дополнительная информация, пожалуйста, дайте мне знать, и я предоставлю.Спасибо

Ответы [ 2 ]

0 голосов
/ 19 февраля 2019

Вы можете перебирать элементы, находя ближайший элемент, у которого 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>
0 голосов
/ 19 февраля 2019

Чтобы определить, что пользователь прокрутил, вы можете прослушать событие scroll в контейнере, который прокручивается.В этом случае это будет корневой элемент, поэтому вы можете использовать window для добавления прослушивателя событий.

Один из способов добиться этого - добавить и удалить scroll прослушиватель в created и destroyed ловушки жизненного цикла, как упоминалось в этом ответе .

Обратите внимание, что событие прокрутки также будет запускаться при запуске прокрутки с помощью window.scroll({...}), а не только прокрутки пользователем,Итак, вам нужно позаботиться об этом.

Я бы порекомендовал добавить какой-нибудь газ в прослушиватель событий scroll, а затем реагировать на все события scroll, после газа, изменив значение currentSection.

ДляНапример, ваш обработчик события scroll может быть:

...,
onScroll(e) {
  if(this.throttle) {
    clearTimeout(this.throttle);
  }

  this.throttle = setTimeout(() => (this.currentSection = this.findCurrentSection(e)), 300);
},
...

Где throttle - просто элемент данных, используемый для хранения значения тайм-аута.Логика поиска значения currentSection будет активирована только через 300 мс после последнего события scroll.Вы также можете использовать requestAnimationFrame, чтобы сделать это, как уже упоминалось здесь .

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 в данном случае).

Вот рабочая скрипка в зависимости от вашего вопроса.Также обратите внимание, что я изменил функцию move в соответствии с внесенными изменениями.

...