Skip to content

Instantly share code, notes, and snippets.

@NickHatBoecker
Created May 30, 2021 15:40
Show Gist options
  • Save NickHatBoecker/fdc13774d09a4ac9beb97130b0964859 to your computer and use it in GitHub Desktop.
Save NickHatBoecker/fdc13774d09a4ac9beb97130b0964859 to your computer and use it in GitHub Desktop.
Navigation Animation in VueJS
<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