Created
May 30, 2021 15:40
-
-
Save NickHatBoecker/fdc13774d09a4ac9beb97130b0964859 to your computer and use it in GitHub Desktop.
Navigation Animation in VueJS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div class="navigation-animation"> | |
<nav class="nav" ref="menu"> | |
<a | |
v-for="(link, index) in links" | |
:key="index" | |
:href="link.url" | |
:class="{ 'link-item': true, 'active': link.active }" | |
>{{ link.title }}</a> | |
<div ref="activeState" class="active-state" /> | |
</nav> | |
</div> | |
</template> | |
<script> | |
export default { | |
data: () => ({ | |
links: [ | |
{ title: 'Home', url: '/home', active: true }, | |
{ title: 'Next page', url: '/navigation1', active: false }, | |
{ title: 'Another page', url: '/somewherelese', active: false }, | |
{ title: 'Exit', url: '/exit', active: false }, | |
], | |
}), | |
mounted () { | |
const menu = this.$refs.menu || null | |
const indicator = this.$refs.activeState || null | |
if (!menu || !indicator) return | |
// Position indicator to active nav item | |
this.resetActiveState() | |
menu.querySelectorAll('.link-item').forEach((link) => { | |
link.addEventListener('mouseover', this.positionActiveState) | |
link.addEventListener('mouseleave', this.resetActiveState) | |
}) | |
}, | |
beforeDestroy () { | |
const menu = this.$refs.menu || null | |
if (!menu) return | |
menu.querySelectorAll('.link-item').forEach((link) => { | |
link.removeEventListener('mouseover', this.positionActiveState) | |
link.removeEventListener('mouseleave', this.resetActiveState) | |
}) | |
}, | |
methods: { | |
positionActiveState (element) { | |
const indicator = this.$refs.activeState || null | |
if (!indicator) return | |
// Update indicator width, based on nav item width | |
indicator.style.width = `${element.target.offsetWidth}px` | |
// Update indicator left position, based on nav item position | |
indicator.style.left = `${element.target.offsetLeft}px` | |
}, | |
resetActiveState () { | |
const menu = this.$refs.menu || null | |
if (!menu) return | |
// Position indicator to active nav item | |
this.positionActiveState({ target: menu.querySelector('.link-item.active') }) | |
}, | |
}, | |
} | |
</script> | |
<style lang="scss" scoped> | |
/** | |
* This one is just for general styling. | |
* You can ignore this. | |
*/ | |
.navigation-animation { | |
height: 100%; | |
width: 100%; | |
background-color: #333; | |
color: #fff; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
} | |
.nav { | |
position: relative; | |
padding: 6px 0; | |
} | |
.link-item { | |
font-size: 20px; | |
color: #fff; | |
text-decoration: none; | |
text-transform: uppercase; | |
margin-right: 20px; | |
&:hover, | |
&:active, | |
&:focus { | |
color: #ff55ff; | |
} | |
} | |
.active-state { | |
position: absolute; | |
opacity: 1; | |
height: 3px; | |
width: 0; | |
left: 0; | |
bottom: 0; // Want the indicator on the top? Just set "top: 0" instead | |
border-bottom: 3px solid #ff55ff; | |
transition: 0.5s ease-in-out; // Manipulate animation speed here | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment