Quasar is a popular Vue UI library for developing good looking Vue apps.
In this article, we’ll take a look at how to create Vue apps with the Quasar UI library.
Intersection Directive
We can watch for element visibility with Quasar’s wrapper on the Intersection Observer API.
For instance, we can write:
<!DOCTYPE html>
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
rel="stylesheet"
type="text/css"
/>
<link
href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
rel="stylesheet"
type="text/css"
/>
</head>
<body class="body--dark">
<style>
.state {
background: #ccc;
font-size: 20px;
color: gray;
padding: 10px;
opacity: 0.8;
}
.observed {
width: 100%;
font-size: 20px;
color: #ccc;
background: #282a37;
padding: 10px;
}
.area {
height: 300px;
}
.filler {
height: 500px;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
<div id="q-app">
<div class="relative-position">
<div class="area q-pa-lg scroll">
<div class="filler"></div>
<div
v-intersection="onIntersection"
class="observed text-center rounded-borders"
>
Observed Element
</div>
<div class="filler"></div>
</div>
<div
class="state rounded-borders text-center absolute-top q-mt-md q-ml-md q-mr-lg text-white"
:class="visibleClass"
>
{{ visible === true ? 'Visible' : 'Hidden' }}
</div>
</div>
</div>
<script>
new Vue({
el: "#q-app",
data: {
visible: false
},
computed: {
visibleClass() {
return `bg-${this.visible ? "positive" : "negative"}`;
}
},
methods: {
onIntersection(entry) {
this.visible = entry.isIntersecting;
}
}
});
</script>
</body>
</html>
We add the v-intersection
directive to run the onIntersection
method went the intersection status changes.
We get the intersection status with the entry.isIntersecting
property.
The handler will run when the div with the directive applied intersections the edge of the scroll container.
We add the visibleClass
computed property to return the class to apply when the visible
reactive property changes.
We can make the onIntersection
method trigger only once with the once
modifier.
Also, we can watch for the intersection percentage by referencing the entry.isIntersection
property:
<!DOCTYPE html>
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
rel="stylesheet"
type="text/css"
/>
<link
href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
rel="stylesheet"
type="text/css"
/>
</head>
<body class="body--dark">
<style>
.state {
background: #ccc;
font-size: 20px;
color: gray;
padding: 10px;
opacity: 0.8;
}
.observed {
width: 100%;
font-size: 20px;
color: #ccc;
background: #282a37;
padding: 10px;
}
.area {
height: 300px;
}
.filler {
height: 500px;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
<div id="q-app">
<div class="relative-position">
<div class="area q-pa-lg scroll">
<div class="filler"></div>
<div
v-intersection="onIntersection"
class="observed text-center rounded-borders"
>
Observed Element
</div>
<div class="filler"></div>
</div>
<div
class="state rounded-borders text-center absolute-top q-mt-md q-ml-md q-mr-lg text-white"
:class="visibleClass"
>
Percent: {{ percent }}%
</div>
</div>
</div>
<script>
new Vue({
el: "#q-app",
data: {
visible: false,
percent: 0
},
computed: {
visibleClass() {
return `bg-${this.visible ? "positive" : "negative"}`;
}
},
methods: {
onIntersection(entry) {
this.visible = entry.isIntersecting;
const percent = (entry.intersectionRatio * 100).toFixed(0);
if (this.percent !== percent) {
this.percent = percent;
}
}
}
});
</script>
</body>
</html>
Also, we can use it to render items that are displayed on the screen:
<!DOCTYPE html>
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
rel="stylesheet"
type="text/css"
/>
<link
href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
rel="stylesheet"
type="text/css"
/>
</head>
<body class="body--dark">
<style>
.item {
height: 200px;
width: 200px;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
<div id="q-app">
<div class="q-pa-md">
<div class="row justify-center q-gutter-sm">
<div
v-for="index in inView.length"
:key="index"
:data-id="index - 1"
class="item q-pa-sm flex flex-center relative-position"
v-intersection="onIntersection"
>
<transition name="q-transition--scale">
<q-card v-if="inView[index - 1]">
<img src="https://cdn.quasar.dev/img/mountains.jpg" />
<q-card-section>
<div class="text-h6">Card #{{ index }}</div>
<div class="text-subtitle2">by John Doe</div>
</q-card-section>
</q-card>
</transition>
</div>
</div>
</div>
</div>
<script>
new Vue({
el: "#q-app",
data: {
inView: Array(50)
.fill()
.map(() => false)
},
methods: {
onIntersection(entry) {
const index = +entry.target.dataset.id;
setTimeout(() => {
this.inView.splice(index, 1, entry.isIntersecting);
}, 50);
}
}
});
</script>
</body>
</html>
All we have to do is call splice
to set the items that are displayed on the screen.
Conclusion
We can watch for intersections with Quasar’s wrapper for the Intersection Observer API.