This post was originally posted on my personal blog π. The source code example also provided in github, given in that blog.
π· Tabs - JS - Vue3 Composition
I have been learning vue2
recently and make my own tabs component in with vue
CLI. In part of my learning process, I also migrate to vue3
using composition API.
Goal
I need to pass all tabs data in parent component, along with the children data, to all child components.
In order to select tab in click event, all the children data should be available in all child components,
The Children Issue
My vue2
design pattern is using slot:
<template>
<tabs>
<tab name="home" title="Home" color="bg-blue-500">
<h3>Home</h3>
<p>Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
Quisque in faucibus magna.</p>
</tab>
β¦
</tabs>
</template>
In children component, the data above will be processed with v-for
:
<template>
<main class="tabs">
<div class="tab-headers">
<div
v-for="tab in tabs" v-bind:key="tab.name"
v-on:click="selectTabByName(tab.name)"
v-bind:class="[activeClass(tab), colorClass(tab)]"
>{{ tab.title }}
</div>
</div>
<div class="tab-spacer"></div>
<div class="tab-contents">
<slot></slot>
</div>
</main>
</template>
The children component is using this line of code.
export default {
name: 'TabListSimple',
data() {
return {
selected: 'news',
tabs: this.$children
};
}
}
As you might have known, the this.$children
has already been deprecated in vue3
. There is no good example,on how to migrate this using the design pattern above.
The Design Pattern
Affter a while, I realize that my problem is not in the this.$children
itself. There must be another way to do this. Then in vue3
, I start to move from data in template to plain javascript.
let tabsArray = [
{ name: 'home', title: 'Home', color: 'bg-blue-500',
text: `Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
Quisque in faucibus magna.` },
β¦
];
export { tabsArray };
At first, I think that this is not an elegant solution, but I continue anyway. My goal is to get the component done in vue3
, so I can start migrate without obstacle. I can change the code later anyway.
Data Provided from Parent
Using provide
and inject
mechanism, preapring all tabs to be used in child component later.
Now I can rewrite the code from scratch using template without data.
<template>
<tabs />
</template>
The data can be provided in parent.
import { provide } from 'vue'
import { tabsArray } from '@/tabsArray.js'
import tabs from '@/components/mockup/TabsMockup.vue'
export default {
name: 'MainMockup',
components: { tabs },
setup() {
provide('tabsArray', tabsArray)
}
}
Composition API with vue3
is very helpful. Although actually you can do it with option API with vue2
.
Data Injected to Children
The children component is still using v-for
as usual, but this time I do not use the slot
feature.
<template>
<main class="tabs">
<div class="tab-headers">
<tabheader
v-for="tab in tabs" v-bind:key="tab.name"
:title="tab.title" :color="tab.color"
:tabname="tab.name"
/>
</div>
<div class="tab-spacer"></div>
<div class="tab-contents">
<tabcontent
v-for="tab in tabs" v-bind:key="tab.name"
:text="tab.text" :title="tab.title" :color="tab.color"
:tabname="tab.name"
/>
</div>
</main>
</template>
The tabs
data in children is available now, by injecting previosly provided tabsArray
.
import { inject } from 'vue'
import tabheader from '@/components/mockup/TabHeaderMockup.vue'
import tabcontent from '@/components/mockup/TabContentMockup.vue'
export default {
name: 'TabsMockup',
components: { tabheader, tabcontent },
setup() {
const tabs = inject('tabsArray')
return { tabs }
}
}
That simple. And that is all.
Preview
Complete Code
You can have a thorough explanation with working code examples, in provided links above.
Closing This Article
This provide
and inject
mechanism is simpler. It is also make sense without magic. But sacrificing slot design pattern might not pleased everbody.
After all I still have so much to learn.
Top comments (0)