I am just wondering, how to structure my code to make my sticky <Header />
component change its background-color
when intersecting with other components (in this case with <Hero />
and <Footer />
.
To make things more complicated, I use vue-router
.
Link to my CodeSandbox
The structure is as follows:
App.vue
<template>
<ul class="nav">
<li>
<router-link to="/">Home</router-link>
</li>
<li>
<router-link to="/about">About</router-link>
</li>
</ul>
<Header />
<router-view />
</template>
views/Home.vue
<template>
<Child1 />
<Child2 />
<Hero />
<Child3 />
<Footer />
</template>
<script>
import Hero from "@/components/Hero";
import Child1 from "@/components/Child1";
import Child2 from "@/components/Child2";
import Child3 from "@/components/Child3";
import Footer from "@/components/Footer";
export default {
components: {
Hero,
Child1,
Child2,
Child3,
Footer,
},
};
</script>
When I follow some tutorials on yt, the authors use the IntersectionObserver
, so I wanted to give it a try:
Header.vue
<template>
<section
class="header"
>
<div class="header__title"
:class="{
header__scroll: isContrastActive,
}"
>
I am an awesome header that is changing it's background colour <br />
when intersecting with other components
</div>
</section>
</template>
<script>
export default {
data() {
return {
isContrastActive: false,
observer: null
};
},
methods: {
activateObserver() {
this.observer = new IntersectionObserver(
([entry]) => {
console.log("isIntersecting: ", entry.isIntersecting);
if (!entry.isIntersecting) {
this.isContrastActive = true;
} else {
this.isContrastActive = false;
}
},
{ rootMargin: "-5% 0px 0px 0px" }
);
document
.querySelectorAll(".observer")
.forEach((el) => this.observer.observe(el));
},
},
mounted() {
this.activateObserver();
},
};
</script>
<style scoped>
.header {
position: sticky;
top: 0;
width: 100vw;
height: auto;
z-index: 10;
}
.header__title {
background-color: yellow;
color: black;
padding: 8px 4px;
text-align: center;
}
.header__scroll {
background-color: orange;
}
</style>
Also added the class="observer"
to the <Hero />
and <Footer />
components.
But it doesn't seem to work.
I have read, that in vue the use of querySelector
is considered to be an antipattern.
If this is the case then how I could structure my code to get what I want?
Thanks in advance
EDIT1:
I noticed, that if I change the text in the <Header />
component and save then everything seems to work just fine.
But on page refresh, it is still not working.
Think that the querySelectorAll
could be the reason.
SOLUTION 1: The most obvious solution is of course:
mounted() {
setTimeout(() => {
this.activateObserver()
}, 500)
},
but it ain't an elegant solution :/.