element-plus的el-tabs组件内容太多,加载太慢的解决方案

仿写element-plus的el-tabs组件,主要为了将tab和内容分开,提高渲染速度

如果tab下的内容太多会导致页面加载异常缓慢

效果和官网一致
在这里插入图片描述

在components文件下新建tabs文件,tabs中新建index.vue

index.vue文件
<template>
  <el-card shadow="Never" body-class="cardCss-table" class="mt-8">
    <div class="tabs__nav-wrap">
      <div class="tabs__nav-scroll">
        <div class="tabs__nav">
          <div class="tabs_active-bar" :style="highlightStyle"></div>
          <div
            v-for="(item, index) in props.tabList"
            :key="item.id"
            @click="changeTabs(item, index)"
            class="c-p tabs__item"
            ref="tabItem"
            :class="{
              p1: index === 0,
              p2: index > 0,
              p3: index === tabList.length - 1 && tabList.length > 1,
              'active-tab': currentId == item.id,
            }"
          >
            <span> {{ item.label }} </span>
            <span v-if="item.num"> {{ "(" + item.num + ")" }}</span>
          </div>
        </div>
      </div>
    </div>
  </el-card>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, nextTick } from "vue";
const props = defineProps({
  tabList: {
    type: Array as any,
    default: () => {
      return [];
    },
  },
});
// props.tabList

const emits = defineEmits(["changeTab"]);
const highlightStyle = ref<any>({
  width: "0px", // 初始化宽度
  transform: "translateX(0px)", // 默认位置
});
const currentId = ref<any>(null);// 当前的高亮id
const tabItem = ref<any>(null); // tabs的ref数组
const changeTabs = (item: any, val: number) => {
  currentId.value = item.id;
  if (val !== 0) {
    let percentage = 0;
    for (let i = 0; i < val; i++) {
      percentage += leftWidth.value[i].leftwidth;
    }
    highlightStyle.value.transform = `translateX(${percentage + 20}px)`;
    highlightStyle.value.width = leftWidth.value[val].width + "px";
  } else {
    highlightStyle.value.transform = `translateX(0px)`;
    highlightStyle.value.width = leftWidth.value[0].width + "px";
  }

  emits("changeTab", item.id);
};

const leftWidth = ref<any[]>([]);// 将每个tabitem长度存储到这个数组中
const calculateWidth = () => {
  const tabItems = tabItem.value;
  tabItems.forEach((item, index) => {
    // console.log(item.offsetWidth, index);
    const offsetWidth = item.offsetWidth;
    let baseWidth = index == 0 || index == tabItems.length - 1 ? offsetWidth - 20 : offsetWidth - 40;
    const width = baseWidth;
    leftWidth.value.push({ width: Number(width), leftwidth: Number(offsetWidth) });
  });
};
onMounted(() => {
// 必须使用setTimeout
  setTimeout(() => {
    currentId.value = props.tabList[0].id; // 默认选中第一个
    calculateWidth(); // 计算tab宽度
    highlightStyle.value.width = leftWidth.value[0].width + "px"; // 设置默认宽度
  }, 200);
});
</script>
<style lang="scss" scoped>
.tabs__nav-wrap {
  height: 40px;
  margin-bottom: -1px;
  overflow: hidden;
  position: relative;
  font-size: 14px;
  color: #303133;
}
.tabs__nav-wrap::after {
  background-color: #e4e7ed;
  bottom: 0;
  content: "";
  height: 2px;
  left: 0;
  position: absolute;
  width: 100%;
  z-index: 1;
}
.tabs__nav-scroll {
  overflow: hidden;
}
.tabs__nav {
  display: flex;
  float: left;
  position: relative;
  transition: transform 0.3s;
  white-space: nowrap;
  z-index: 2;
}
.tabs__item {
  align-items: center;
  box-sizing: border-box;
  display: flex;
  font-weight: 500;
  height: 40px;
  justify-content: center;
  list-style: none;
  position: relative;
}
.p1 {
  padding: 0 20px 0 0;
}
.p2 {
  padding: 0 20px;
}
.p3 {
  padding: 0 0 0 20px;
}

.tabs_active-bar {
  background-color: #409eff;
  bottom: 0;
  height: 2px;
  left: 0;
  list-style: none;
  position: absolute;
  transition: width 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), transform 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
  z-index: 1;
}
.active-tab {
  color: #409eff;
}
</style>

在使用此组件的.vue文件中使用Tabs组件

<template>
  <div>
    <!-- Tabs组件-->
    <Tabs :tabList="ebTabsList" @changeTab="changeTab" />
    ...其他内容
  </div>
</template>
<script setup lang="ts">
import Tabs from "@/components/tabs/index.vue";
interface Tabs {
  label: string;
  id: string;
}
const tabData = ref<Tabs[]>([
  { label: "待下单", id: "1" },
  { label: "异常订单", id: "2" },
]);
</script>

适用于使用el-tabs组件但是内容太多的场景,如果想要包裹到一起再在外层包裹el-card,ui样式基本和element-plus的一样

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值