feat: add tabs component

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/3445/head
Ryan Wang 2022-04-29 15:15:09 +08:00
parent 2bb7a1e963
commit 1e350ecad4
5 changed files with 147 additions and 20 deletions

View File

@ -1,5 +1,25 @@
<script lang="ts" setup></script>
<script lang="ts" setup>
import { computed, inject } from "vue";
import type { ComputedRef } from "vue";
const props = defineProps({
id: {
type: String,
},
label: {
type: String,
},
});
const activeId = inject<ComputedRef<string | number | undefined>>("activeId");
const isActive = computed(() => {
return activeId?.value === props.id;
});
</script>
<template>
<div>tab item</div>
<div v-if="isActive">
<slot />
</div>
</template>
<style lang="scss"></style>

View File

@ -3,11 +3,11 @@ import { VTabbar } from "./index";
function initState() {
return {
active: "johnniang",
activeId: "johnniang",
items: [
{ label: "Ryan Wang", value: "ryanwang" },
{ label: "JohnNiang", value: "johnniang" },
{ label: "guqing", value: "guqing" },
{ label: "Ryan Wang", id: "ryanwang" },
{ label: "JohnNiang", id: "johnniang" },
{ label: "guqing", id: "guqing" },
],
};
}
@ -16,20 +16,20 @@ function initState() {
<Story title="Tabbar" :init-state="initState">
<template #default="{ state }">
<div class="p-3">
<VTabbar :items="state.items" v-model:active="state.active" />
<VTabbar :items="state.items" v-model:activeId="state.activeId" />
</div>
<div class="p-3">
<VTabbar
type="pills"
:items="state.items"
v-model:active="state.active"
v-model:activeId="state.activeId"
/>
</div>
<div class="p-3">
<VTabbar
type="outline"
:items="state.items"
v-model:active="state.active"
v-model:activeId="state.activeId"
/>
</div>
</template>

View File

@ -4,7 +4,7 @@ import { computed } from "vue";
import type { Type } from "./interface";
const props = defineProps({
active: {
activeId: {
type: [Number, String],
},
items: {
@ -14,9 +14,9 @@ const props = defineProps({
type: String as PropType<Type>,
default: "default",
},
valueKey: {
idKey: {
type: String,
default: "value",
default: "id",
},
labelKey: {
type: String,
@ -24,15 +24,15 @@ const props = defineProps({
},
});
const emit = defineEmits(["update:active", "change"]);
const emit = defineEmits(["update:activeId", "change"]);
const classes = computed(() => {
return [`tabbar-${props.type}`];
});
const handleChange = (value: number | string) => {
emit("update:active", value);
emit("change", value);
const handleChange = (id: number | string) => {
emit("update:activeId", id);
emit("change", id);
};
</script>
<template>
@ -42,8 +42,8 @@ const handleChange = (value: number | string) => {
v-for="(item, index) in items"
:key="index"
class="tabbar-item"
:class="{ 'tabbar-item-active': item[valueKey] === active }"
@click="handleChange(item[valueKey])"
:class="{ 'tabbar-item-active': item[idKey] === activeId }"
@click="handleChange(item[idKey])"
>
<div v-if="item.icon" class="tabbar-item-icon">
<component :is="item.icon" />

View File

@ -0,0 +1,49 @@
<script lang="ts" setup>
import { VTabs, VTabItem } from "./index";
</script>
<template>
<Story title="Tabs" :init-state="() => ({ activeId: 'ryanwang' })">
<template #default="{ state }">
<div class="p-3">
<VTabs v-model:activeId="state.activeId">
<VTabItem label="JohnNiang" id="johnniang">
This is JohnNiang's Item
</VTabItem>
<VTabItem label="Ryan Wang" id="ryanwang">
This is Ryan Wang's Item
</VTabItem>
<VTabItem label="guqing" id="guqing">
This is guqing's Item
</VTabItem>
</VTabs>
</div>
<div class="p-3">
<VTabs v-model:activeId="state.activeId" type="pills">
<VTabItem label="JohnNiang" id="johnniang">
This is JohnNiang's Item
</VTabItem>
<VTabItem label="Ryan Wang" id="ryanwang">
This is Ryan Wang's Item
</VTabItem>
<VTabItem label="guqing" id="guqing">
This is guqing's Item
</VTabItem>
</VTabs>
</div>
<div class="p-3">
<VTabs v-model:activeId="state.activeId" type="outline">
<VTabItem label="JohnNiang" id="johnniang">
This is JohnNiang's Item
</VTabItem>
<VTabItem label="Ryan Wang" id="ryanwang">
This is Ryan Wang's Item
</VTabItem>
<VTabItem label="guqing" id="guqing">
This is guqing's Item
</VTabItem>
</VTabs>
</div>
</template>
</Story>
</template>

View File

@ -1,5 +1,63 @@
<script lang="ts" setup></script>
<script lang="ts" setup>
import { computed, provide, useSlots } from "vue";
import type { PropType, ComputedRef } from "vue";
import { VTabbar } from "./index";
import type { Type } from "@/components/base/tabs/interface";
const props = defineProps({
activeId: {
type: [Number, String],
},
type: {
type: String as PropType<Type>,
default: "default",
},
idKey: {
type: String,
default: "id",
},
labelKey: {
type: String,
default: "label",
},
});
provide<ComputedRef<string | number | undefined>>(
"activeId",
computed(() => props.activeId)
);
const emit = defineEmits(["update:activeId", "change"]);
const slots = useSlots();
const tabItems = computed(() => {
return slots.default?.().map(({ props: slotProps }) => {
return {
id: slotProps?.[props.idKey],
label: slotProps?.[props.labelKey],
};
});
});
const handleChange = (id: string | number) => {
emit("update:activeId", id);
emit("change", id);
};
</script>
<template>
<div>tabs</div>
<div class="tabs-wrapper">
<div class="tabs-bar-wrapper">
<VTabbar
:activeId="activeId"
:items="tabItems"
:type="type"
@change="handleChange"
/>
</div>
<div class="tabs-items-wrapper">
<slot />
</div>
</div>
</template>
<style lang="scss"></style>