<div id="app">
<div class="sections-menu">
<span class="menu-point" v-bind:class="{active: activeSection == index}" v-on:click="scrollToSection(index)" v-for="(offset, index) in offsets" v-bind:key="index" v-title="
'Go to section ' + (index+1)">
</span>
</div>
<section class="fullpage blue">
<h1>Vue.js Fullpage Scroll</h1>
<p>by <a href="https://webdeasy.de/?referer=cp-NVOEBL" target="_blank">webdeasy.de</a></p>
</section>
<section class="fullpage black">
<h1>Section 2</h1>
<p>made with <a href="https://vuejs.org/" target="_blank">Vue.js</a></p>
</section>
<section class="fullpage red">
<h1>Section 3</h1>
<p>works on <span><b>desktop & mobile</b></span> devices</p>
</section>
<section class="fullpage purple">
<h1>Section 4</h1>
<p>tested in all <span><b>modern browsers</b></span></p>
</section>
<section class="fullpage green">
<h1>Section 5</h1>
<p>check the tutorial <a href="https://webdeasy.de/en/programming-vue-js-fullpage-scroll/?referer=cp-NVOEBL" target="_blank">here</a></p>
</section>
</div>
body {
margin: 0;
color: #FFF;
font-family: Helvetica, arial, sans-serif;
overflow: hidden;
}
h2 {
position: fixed;
}
.fullpage {
height: 100vh;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
h1 {
font-size: 6em;
margin: 0;
text-align: center;
padding: 0 1rem;
}
p {
font-size: 1em;
}
.fullpage a, .fullpage span {
text-decoration: none;
font-weight: 600;
background: rgba(255, 255, 255, 0.2);
padding: 5px 10px;
color: #FFF;
margin-left: 5px;
}
.red {
background-color: #ab4545;
}
section.black {
background-color: #000;
}
.blue {
background-color: #237ad4;
}
.green {
background-color: #5E9F6D;
}
.purple {
background-color: #42325B;
}
h1.black {
color: #000;
}
.sections-menu {
position: fixed;
right: 1rem;
top: 50%;
transform: translateY(-50%);
}
.sections-menu .menu-point {
width: 10px;
height: 10px;
background-color: #FFF;
display: block;
margin: 1rem 0;
opacity: .6;
transition: .4s ease-in-out all;
cursor: pointer;
}
.sections-menu .menu-point.active {
opacity: 1;
transform: scale(1.5);
}
.sections-menu .menu-point:hover {
opacity: 1;
transform: scale(1.2);
}
@media screen and (max-width: 1200px) {
h1 {
font-size: 2.5em;
}
}
var app = new Vue({
el: '#app',
data: {
inMove: false,
inMoveDelay: 400,
activeSection: 0,
offsets: [],
touchStartY: 0
},
methods: {
/**
* Calcaulates the absolute offsets of each section on the page and pushs it into the offsets array
*/
calculateSectionOffsets() {
let sections = document.getElementsByTagName('section');
let length = sections.length;
for(let i = 0; i < length; i++) {
let sectionOffset = sections[i].offsetTop;
this.offsets.push(sectionOffset);
}
},
/**
* Handle the 'mousewheel' event for other browsers
*/
handleMouseWheel: function(e) {
if (e.wheelDelta < 30 && !this.inMove) {
this.moveUp();
} else if (e.wheelDelta > 30 && !this.inMove) {
this.moveDown();
}
e.preventDefault();
return false;
},
/**
* Handle the 'DOMMouseScroll' event for Firefox
*/
handleMouseWheelDOM: function(e) {
if (e.detail > 0 && !this.inMove) {
this.moveUp();
} else if (e.detail < 0 && !this.inMove) {
this.moveDown();
}
return false;
},
/**
* Move to the previous section or the last section if you're on the first section
*/
moveDown() {
this.inMove = true;
this.activeSection--;
if(this.activeSection < 0) this.activeSection = this.offsets.length - 1;
this.scrollToSection(this.activeSection, true);
},
/**
* Move to the next section or the first section if you're on the last section
*/
moveUp() {
this.inMove = true;
this.activeSection++;
if(this.activeSection > this.offsets.length - 1) this.activeSection = 0;
this.scrollToSection(this.activeSection, true);
},
/**
* Scrolls to the passed section id if the section exists and the delay is over
*/
scrollToSection(id, force = false) {
if(this.inMove && !force) return false;
this.activeSection = id;
this.inMove = true;
// get section and scroll into view if it exists
let section = document.getElementsByTagName('section')[id];
if(section) {
document.getElementsByTagName('section')[id].scrollIntoView({behavior: 'smooth'});
}
setTimeout(() => {
this.inMove = false;
}, this.inMoveDelay);
},
/**
* Handles the 'touchstart' event on mobile devices
*/
touchStart(e) {
e.preventDefault();
this.touchStartY = e.touches[0].clientY;
},
/**
* Handles the 'touchmove' event on mobile devices
*/
touchMove(e) {
if(this.inMove) return false;
e.preventDefault();
const currentY = e.touches[0].clientY;
if(this.touchStartY < currentY) {
this.moveDown();
} else {
this.moveUp();
}
this.touchStartY = 0;
return false;
}
},
/**
* mounted() hook executes after page load and call the section offset calculation and registers all events
*/
mounted() {
this.calculateSectionOffsets();
window.addEventListener('DOMMouseScroll', this.handleMouseWheelDOM); // Mozilla Firefox
window.addEventListener('mousewheel', this.handleMouseWheel, { passive: false }); // Other browsers
window.addEventListener('touchstart', this.touchStart, { passive: false }); // mobile devices
window.addEventListener('touchmove', this.touchMove, { passive: false }); // mobile devices
},
/**
* destroyed() hook executes on page destroy and removes all registered event listeners
*/
destroyed() {
window.removeEventListener('DOMMouseScroll', this.handleMouseWheelDOM); // Mozilla Firefox
window.removeEventListener('mousewheel', this.handleMouseWheel, { passive: false }); // Other browsers
window.removeEventListener('touchstart', this.touchStart); // mobile devices
window.removeEventListener('touchmove', this.touchMove); // mobile devices
}
});
This Pen doesn't use any external CSS resources.