vue标签

该代码示例展示了如何在Vue.js应用中创建一个Tab组件,包含TabPanel子组件,用于根据category属性切换显示不同的badElements内容。组件使用ref进行引用,通过事件处理函数handleTabs更新选中标签。
摘要由CSDN通过智能技术生成

app.vue

<template>
    <div style="width: 700px;">
      <Tab :default="data[0].catagory" ref="tabsCustom" @tabs-click="handleTabs">
        <TabPanel v-for="(item) of data" :key="item.badElements" :title="item.catagory" :name="item.catagory">
          <div>{{ item.badElements }} </div>
        </TabPanel>
      </Tab>
    </div>
  </template>
  
  <script setup>
  import { ref } from 'vue';
  import Tab from '@/components/Tab.vue';
  import TabPanel from '@/components/TabPanel.vue';
  
  const data = ref([
    {
      catagory: "name1",
      badElements: "12341"
    },
    {
      catagory: "name2",
      badElements: "12342"
    },
    {
      catagory: "name3",
      badElements: "12343"
    },
    {
      catagory: "name4",
      badElements: "12344"
    },
    {
      catagory: "name5",
      badElements: "12345"
    },
  ])
  </script>
  
  <style>
  </style>

Tab.vue

<template>
    <div class="card text-center" :style="{ maxWidth: 650 + 'px' }">
        <div class="card-header">
            <ul class="nav card-header-tabs">
                <li class="nav-item" v-for="(titleInfo, index) in titles" :key="index"
                    :class="{ 'active-style': titleInfo.title === currentTab }"
                    @click.prevent="selectTab(titleInfo.title, index)">
                    <a class="nav-link" href="#" :ref="ref => navLink[index] = ref">{{ titleInfo.title }}</a>
                </li>
            </ul>
            <div class="underline">
                <li :style="{ left: updateLeft + 'px', width: underlineWidth + 'px' }"></li>
            </div>
        </div>
        <div class="card-body">
            <slot></slot>
        </div>
    </div>
</template>
<script setup lang="ts">
import { onMounted, provide, ref, defineProps, nextTick, useContext, onUpdated } from 'vue';
import { toRaw } from '@vue/reactivity'

// const emit = defineEmits(['tabs-click']);
const { slots } = useContext();
const props = defineProps({
    default: {
        type: String,
        default: '',
        required: false,
    },
});
const updateLeft = ref(0);
// const navLink = ref<HTMLElement | null>(null);
const navLink = ref([]);
const navLinkWidth = ref(0);
const underlineWidth = ref(0);
const currentTab = ref(props.default);
const titles = ref([]);
// console.log("name", name);
console.log("currenTab", currentTab.value);
const selectTab = (name: string, titleIndex: number) => {

    // console.log("navLink", navLink.value);
    // console.log("currenTab", currentTab.value);
    currentTab.value = name;
    navLinkWidth.value = navLink.value[titleIndex].clientWidth;
    underlineWidth.value = navLinkWidth.value * 0.8;
    if (titleIndex === 0) {
        updateLeft.value = 0;
    } else {
        updateLeft.value = navLink.value[titleIndex].offsetLeft;
    }
};
onMounted(() => {
    console.log("onMounted", navLink.value);
    console.log("slots", slots.default()[0].children);
    titles.value = slots.default()[0].children.map(({ props }) => {
        if (props) {
            const { title, name } = props;
            return {
                title,
                name,
            };
        }
    });
    console.log("titles", titles.value);
    const defaultTab = titles.value.find((child: { name: any }) => child.name === currentTab.value);
    if (defaultTab) {
        currentTab.value = defaultTab.name;
    } else if (titles.value.length > 0) {
        currentTab.value = titles.value[0].name;
    }

});
onUpdated(() => {
    console.log("onUpdated", navLink.value[0]);
    const titleIndex = titles.value.findIndex((item: { name: any }) => item.name === currentTab.value);
    const index = titles.value.findIndex((item: { name: any }) => item.name === currentTab.value);
    console.log("a标签", navLink.value[0]);
    navLinkWidth.value = navLink.value[index].clientWidth;
    underlineWidth.value = navLinkWidth.value * 0.8;
    if (titleIndex === 0) {
        updateLeft.value = 0;
    } else {
        updateLeft.value = navLink.value[titleIndex].offsetLeft;
    }

});

provide('currentTab', currentTab);

</script>
  
<style scoped>
.active-style {
    box-shadow: -3px -3px 3px 3px rgba(209, 204, 204, 0.47);
    border-radius: 10%;
};

.underline {
    position: relative;
    li {
        transition: all 0.4s ease;
        height: 3px;
        background-color: rgb(126, 225, 225);
        position: absolute;
        a {
            box-sizing: border-box;
        };
    };
};
</style>

TabPanel.vue

<template>
    <div v-if="currentTab === name">
        <slot></slot>
    </div>
</template>
<script setup lang="ts">
import { inject, defineProps } from 'vue';

const props = defineProps({
    title: {
        type: String,
        require: true,
    },
    name: {
        type: String,
        require: true,
    },
});
console.log("props", props);
const currentTab = inject('currentTab');
</script>
<style scoped></style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值