我正在实现一个按钮,单击该按钮可以垂直向下滚动一位团队成员。到目前为止,我已经设法一键向下滚动一位团队成员,但是当用户手动滚动回到顶部时代码会中断。
这里在工作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'
});
}
}
}
};
如何检测到用户已向上滚动并更改了当前部分的值?如果您有其他任何信息,请让我知道,我会提供。谢谢
答案 0 :(得分:1)
要检测到用户已滚动,可以侦听正在滚动的容器上的scroll
事件。在这种情况下,这将是根元素,因此您可以使用window
添加事件侦听器。
实现这一目标的一种方法是在scroll
和created
生命周期挂钩中添加和删除destroyed
侦听器,如in this answer所述。
请注意,当您使用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
事件后 后300ms触发寻找scroll
值的逻辑。您还可以使用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
({ {1}})。
根据您的问题,这里是working fiddle。另外请注意,我已经根据引入的更改修改了e
函数。
答案 1 :(得分: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>