Reputation: 2529
I've vuetify tabs implemented with vue-scrollto that when you click a tab it will scroll to a position.
<v-tabs
centered
grow
color="#009EE2"
>
<div class="slider-background" />
<v-tabs-slider />
<v-tooltip
bottom
v-for="(tab, key) in tabs"
:key="key"
color="#009EE2"
>
<template v-slot:activator="{on}">
<v-tab
v-on="on"
v-scroll-to="{
el: tab.scrollTo,
container: scrollContainer,
duration: 300,
easing: 'linear',
offset: -120,
force: true,
cancelable:true
}"
>
<v-icon v-text="tab.icon" />
</v-tab>
</template>
<div class="v-tooltip-arrow" />
<span>
{{ $t(tab.tooltipText) }}
</span>
</v-tooltip>
</v-tabs>
So what I want to achieve now is that when scrolling the active tab changes depending on the position.
I've searched for days and I haven't found anything. documentation
Is there a way without using JQuery?
Result example with JQuery: http://jsfiddle.net/cse_tushar/Dxtyu/141/
Upvotes: 4
Views: 8762
Reputation: 101
This is how I have achieved it successfully without using any external library like vue-scrollto.
Tabs -
<v-tabs vertical v-model="tab_selected" >
<span v-for="(category, index) in categories" :key="index">
<v-tab @click="$vuetify.goTo('#sec_'+index)" class="nav_tab">
{{category.name}}
</v-tab>
</span>
</v-tabs>
Here I have bound the tab selection to a v-model and the scroll to the required div happens with $vuetify.goTo() (more here - https://vuetifyjs.com/en/features/scrolling/)
The Scrollable content is held in a free flowing div -
<div v-for="(category, index) in categories" :key="index">
<v-card :id="'sec_'+index" class="card-shadow mb-10">
<span :id="'span_'+index" v-intersect="handleIntersect"></span>
...
</v-card>
</div>
In the above scanario, the tabs and the scrollable content are held in a col-4 and a col-8 respectively.
There are 2 parts to this. On clicking of the tab, the div should scroll to the correct content. This is handled by $vuetify.goTo(). the second is on scrolling the content div, the relevant tab should be selected. This is handled by the v-intersect directive. (more here - https://vuetifyjs.com/en/directives/intersect/)
<span :id="'span_'+index" v-intersect="handleIntersect"></span>
The handleIntent function will fire when the said span is in and out of view. In the handleIntent function, I detect the index of the span which is in view and then activate the tab via v-model.
handleIntersect(entries, observer){
let intersecting_element = entries[0]
if(intersecting_element.isIntersecting){
let id = intersecting_element.target.id
let index = Number(id.split("_")[1])
this.tab_selected = index
}
}
This is how it looks - https://gyazo.com/388550a03d66e086d7dc00b646264806
Cheers!
Upvotes: 3
Reputation: 2411
By combining the href
attribute for tabs, and an intersection observer, you can accomplish this.
Here's a rudimentary, but working, pen: https://codepen.io/Qumez/pen/VwYEapg
Effectively, what we're doing here is assigning an anchor to each tag, and tying that to a data property. Then, we have a span at the bottom of the page with an intersection observer, using Vuetify's v-intersect
wrapper:
<span v-intersect ="handleIntersect">Page will automatically scroll to tab-3 when this span is in view</span>
This intersect wrapper calls a user-defined method (in this case, handleIntersect
) to update the tab:
handleIntersect(entries, observer) {
if(entries[0].isIntersecting) {
this.tab = "tab-3"
}
else {
this.tab = "tab-1"
}
}
For your use case, maybe each item that would change a tab based on its viewport position would need to call a given function with an argument for which tab to set. That's not much of a stretch from where this Pen is currently.
Note: I've never used IntersectionObserver and I'm not certain if isIntersecting
is the best way to detect an element's existence in the viewport, so do your own research and testing before implementing this in production code :)
Upvotes: 5