Starting out with VueJS, making a small fun project. The project is a simple static portfolio website, with a navigation bar at the top and a bootstrap scrollspy, jumping to the different sections (I took this template as inspiration for the looks).
Here is the problem:
The top of the page in my case has a background image covering the whole viewport. I find it looks quite good in my case to add a bit of opacity to the navbar (which is fixed to the top in order to be always visible). However, when scrolling down, text from the content is interfering with the logo and text from the navbar, so I want to switch to a solid background.
Here is my solution:
I wanted to dynamically switch the bootstrap class bg-opacity-75
used in the navbar on and of based on the events fired by the scrollspy. Since I have every section in my scrollable website built as a separate vue component I needed to have a "global" state of the background. For this I read and combined information from the bootstrap and vuejs documentation.
Here is what my App.vue
looks like:
<template>
<NavigationComponent />
<div
data-bs-spy="scroll"
data-bs-target="#navbar-main"
data-bs-root-margin="0px 0px -40%"
data-bs-smooth-scroll="true"
tabindex="0"
>
<HomeComponent />
<UnternehmenComponenet />
<LeistungenComponent />
<ReferenzenComponent />
<KontaktComponent />
</div>
</template>
<script setup>
import NavigationComponent from './components/NavigationComponent.vue'
import HomeComponent from './components/HomeComponenet.vue'
import UnternehmenComponenet from './components/UnternehmenComponenet.vue'
import LeistungenComponent from './components/LeistungenComponent.vue'
import ReferenzenComponent from './components/ReferenzenComponent.vue'
import KontaktComponent from './components/KontaktComponent.vue'
import { onMounted } from 'vue'
import {store} from './assets/js/store.js'
onMounted(() =>
{
const firstScrollSpyEl = document.querySelector('[data-bs-spy="scroll"]')
firstScrollSpyEl.addEventListener('activate.bs.scrollspy', (e) => {
if(e.relatedTarget.text){
store.isNavbarBackgroundTransparent = false;
}
else {
store.isNavbarBackgroundTransparent = true;
}
})
});
</script>
Each of the components contains a div
which the id for the scroll target.
store.js
is just simple file containing my global state:
import { reactive } from 'vue'
export const store = reactive({ isNavbarBackgroundTransparent: true })
The navigation component contains the navbar with the scrollspy:
<template>
<nav
id="navbar-main"
class="navbar navbar-nav-scroll navbar-expand-lg fixed-top border-bottom bg-light"
:class="{
'bg-opacity-75': store.isNavbarBackgroundTransparent,
}"
>
<div class="container">
<a
class="navbar-brand"
href="#Home"
>
<img
class="main-logo"
src="/src/assets/img/logo.png"
>
</a>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarCollapse"
aria-controls="navbarCollapse"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon" />
</button>
<div
id="navbarCollapse"
class="collapse navbar-collapse"
>
<div class="navbar-nav">
<a
class="nav-link"
href="#Unternehmen"
>Unternehmen</a>
<a
class="nav-link"
href="#Leistungen"
>Leistungen</a>
<a
class="nav-link"
href="#Referenzen"
>Referenzen</a>
<a
class="nav-link"
href="#Kontakt"
>Kontakt</a>
</div>
</div>
</div>
</nav>
</template>
<script setup>
import {store} from '../assets/js/store.js'
</script>
Where/why am I unsure about the solution
The solution works quite fine; there are no issues really. I am just not sure, because I have read some docs and forum posts, that using vanilla events outside of the respective frameworks might lead to some issues. On the other hand I have also read some posts, that with bootstrap 5 this is not the case anymore. I initially wanted to use the event system provided by Vuejs directly but after searching the docs for quite a while, I gave up.