tabs组件封装

Tabs组件封装

封装到tabs组件,最简单的方式肯定是写几个div,内容和导航栏写在一起。例如

  <div :class="{'active':index===1}">1</div>
  <div :class="{'active':index===2}">2</div>
  <div :class="{'active':index===3}">3</div>
  <div :class="{'active':index===4}">4</div>

但这样,逻辑代码和业务逻辑就没有彻底分开。因此,实现tab栏的最佳逻辑就是逻辑代码和业务逻辑相隔离。采用Element-plus的那种方法:

<el-tabs type="border-card">
  <el-tab-pane label="用户管理">用户管理</el-tab-pane>
  <el-tab-pane label="配置管理">配置管理</el-tab-pane>
  <el-tab-pane label="角色管理">角色管理</el-tab-pane>
  <el-tab-pane label="定时任务补偿">定时任务补偿</el-tab-pane>
</el-tabs>

下面来自己手动封装一个.

该组件封装的几个关键点:

  1. provideinject。至于为什么不用props传递,因为props会导致数据出现响应式丢失。
  2. useSlots获取到所有插槽的内容信息。

Tabs组件

<template>
  <!-- 我是tabs页面 -->
  <div class="tabsShow">
    <div
      class="item"
      v-for="(item, index) in childrenProps"
      :key="index"
      @click="handleSelectTab(item.name)"
      :class="[{ active: active === item.name }]"
    >
      {{ item.name }}
    </div>
  </div>

  <div class="slot"><slot></slot></div>
</template>

<script setup>
import { useSlots, onMounted, ref, provide } from "vue";
const props = defineProps(["modelValue"]);
const emit = defineEmits(["handleClick"]);
const slots = useSlots();
const childrenProps = ref([]); // 子组件的标题
const active = ref(""); // 下标
provide("active", active);
const handleSelectTab = (name) => {
  active.value = name;

  emit("handleClick", active.value);
};
onMounted(() => {
  console.log(slots.default());
  slots.default().forEach((item, index) => {
    childrenProps.value.push(item.props);
  });
  active.value = slots.default()[0].props.name;
  console.log(childrenProps.value);
});
console.log(props);
</script>
<style lang="scss" scoped>
div {
  box-sizing: border-box;
}
.tabsShow {
  cursor: pointer;
  display: flex;
  height: 50px;
  border: 1px solid rgba($color: #000000, $alpha: 0.1);
  justify-content: flex-start;
  .item {
    border-left: 1px solid rgba(0, 0, 0, 0.1);
    border-right: 1px solid rgba($color: #000000, $alpha: 0.1);
    padding: 5px 10px;
    height: 100%;
    width: fit-content;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .active {
    background-color: rgba(0, 0, 0, 0.15);
  }
}
.slot {
}
</style>

pane组件

<template>
  <div v-if="activeName == name"><slot></slot></div>
</template>

<script setup>
import { inject, defineProps, ref, watch } from "vue";
const activeName = inject("active");
console.log(activeName);
const props = defineProps(["label", "name"]);
</script>
<style lang="scss" scoped></style>

对此,基本的功能已经完成。如果有样式的需求,可以继续在上面进行封装。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值