I was trying to improve tabsWrapper component with adding button by clicking on which the next tab is selected. But it turned out that my code doesn't work at all even though I've used known by me patterns. But a lack of knowledge related to slots, inject and provide didn't give me any results . So, I need yourr help.
<template>
<div class="tab-content" v-show="title == selectedTitle || tabTitles[index] == selectedTitle" >
<slot />
</div>
</template>
<script>
import { inject } from 'vue';
export default{
props:['title'],
setup(){
const selectedTitle=inject('selectedTitle')
const tabTitles = inject('tabTitles')
const index=inject('index')
return{
selectedTitle,
tabTitles, index
}
},
}
</script>
<style scoped>
.tab-content{
padding: 20px;
}
</style>
This is my tab component in which I inject index string and tabTitles array from my TabsWrapper component and also added v-show to conditionally render each new tab if value if index is changed from my TabsWrapper component
<template>
<div class="tabs">
<div class="tab_header">{{ title }}</div>
<ul class="tabs_header">
<li
v-for="title in tabTitles"
:key="title"
@click="selectedTitle = title"
:class="{ selected: title == selectedTitle}"
>
{{ title }}
</li>
<li @click="next">Next</li>
</ul>
<slot />
</div>
</template>
<script lang="js">
import { ref } from "vue";
import { provide } from "vue";
export default {
setup(props, { slots }) {
const tabTitles = ref(slots.default().map((tab) => tab.props.title));
const selectedTitle = ref(tabTitles.value[0]);
const index = ref(0)
function next(){
index.value++
}
provide ("tabTitles", tabTitles)
provide("selectedTitle", selectedTitle);
provide("index", index)
return {
selectedTitle,
tabTitles, index, next
};
},
props:["title"],
created(){
console.log(this.title)
},
};
</script>
<style scoped>
.tabs {
overflow: hidden;
width: auto;
border-radius: 60px;
background-color: #fff;
box-shadow: rgba(9, 30, 66, 0.25) 0px 4px 8px -2px,
rgba(9, 30, 66, 0.08) 0px 0px 0px 1px
}
.tabs_header {
margin-top: 10px;
margin-bottom: 10px;
list-style: none;
padding: 0;
display: flex;
}
.tabs_header li {
font-weight: 900;
width: auto;
text-align: center;
padding: 1vmin 4vmin;
margin-right: 10px;
background-color: white;
box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px,
rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;
border-radius: 60px;
cursor: pointer;
transition: 0.4s all ease-out;
color: #000;
}
.tabs_header li.selected {
background-color: #cf1c86;
color: white;
}
.tab_header {
background-color: #cf1c86;
color: white;
justify-content: center;
text-align: center;
font-size: 3vh;
font-family: "Signika", sans-serif;
}
@media screen and (max-width: 1024px){
.tabs_header li{
padding: 1vmin 1vmin;
font-size: 0.8rem;
}
.tabs{
width: auto;
}
}
</style>
To be honest, I'm not that good user of composition API and this pattern that I used for incrementing value of index I found on the official docs of Vue.js. As you see, this function has to increment value of index. And if the next selectedTitle equals one of TabTitles in array,the next tab has to be shown. But, as you see, my lack knowledge fulfilled my need Also, when I click on the button next, I keep getting:
[Vue warn]: Maximum recursive updates exceeded. This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.