vue3封装swicthtab组件 js&&ts可用

在这里插入图片描述

直接上代码

<template>
  <div class="switchTab">
    <ul class="container">
      <li
        class="switchItem"
        ref="switchItem"
        v-for="(item, index) in FDATA.tabList || tabList"
        @click="liHandle(index)"
        :key="item.text"
      >
        <span class="icon">
          <i :class="item.icon"></i>
        </span>
        <span class="text">{{ item.text }}</span>
      </li>
      <div class="background"></div>
    </ul>
  </div>
</template>
<!--ts代码-->
<script lang="ts" setup>
//引入onMounted和ref
import { onMounted, ref } from "vue";

// 父组件传过来的tab栏选渲染数组和默认选中;
let FDATA = defineProps({
  tabList: {
    type: Array,
  },
  num: {
    type: Number,
  },
  color: {
    type: String,
    default: "#da1e5d",
  },
});
// 若父组件未传递tab栏选渲染数组则使用默认
const tabList: Array<object> = [
  {
    icon: "el-icon-s-home",
    text: "首页",
  },
  {
    icon: "el-icon-s-grid",
    text: "分类",
  },
  {
    icon: "el-icon-share",
    text: "分享",
  },
  {
    icon: "el-icon-s-order",
    text: "清单",
  },
  {
    icon: "el-icon-user-solid",
    text: "我的",
  },
];
const switchItem = ref(null);
//使用onMounted在页面加载结束默认给传入数值的标签生效,若并未传入生效标签下标则默认第一个
onMounted(() => {
  switchItem.value &&
    (switchItem.value[FDATA.num ? FDATA.num - 1 : 0] as any).classList.add(
      "active"
    );
});
//li标签点击事件  进行排他操作
const liHandle = function (i: number): void {
  let domList = document.querySelectorAll(".switchItem");
  domList.forEach((item, index) => {
    if (i === index) {
      item.classList.add("active");
    } else {
      item.classList.remove("active");
    }
  });
};
</script>


<!--js代码-->
<!--<script setup>
//引入onMounted和ref
import { onMounted, ref } from "vue"
// 父组件传过来的tab栏选渲染数组和默认选中;
let FDATA = defineProps({
  tabList: {
    type: Array
  },
  num: {
    type: Number,
  },
})
// 若父组件未传递tab栏选渲染数组则使用默认
const tabList = [
  {
    icon: "el-icon-s-home",
    text: "首页",
  },
  {
    icon: "el-icon-s-grid",
    text: "分类",
  },
  {
    icon: "el-icon-share",
    text: "分享",
  },
  {
    icon: "el-icon-s-order",
    text: "清单",
  },
  {
    icon: "el-icon-user-solid",
    text: "我的",
  },
]
const switchItem = ref(null)
//使用onMounted在页面加载结束默认给传入数值的标签生效,若并未传入生效标签下标则默认第一个
onMounted(() => {
  switchItem.value[FDATA.num - 1 || 0].classList.add(
    "active"
  )
})
//li标签点击事件  进行排他操作
const liHandle = function (i) {
  let domList = document.querySelectorAll(".switchItem")
  domList.forEach((item, index) => {
    if (i === index) {
      item.classList.add("active")
    } else {
      item.classList.remove("active")
    }
  })
};
</script>-->
<style lang="scss" scoped>
* {
  caret-color: rgba(0, 0, 0, 0);
}
@keyframes shake {
  10% {
    transform: rotate(5deg);
  }
  20% {
    transform: rotate(-5deg);
  }
  30% {
    transform: rotate(5deg);
  }
  40% {
    transform: rotate(-5deg);
  }
  50% {
    transform: rotate(5deg);
  }
  60% {
    transform: rotate(-5deg);
  }
  70% {
    transform: rotate(5deg);
  }
  80% {
    transform: rotate(-5deg);
  }
  90% {
    transform: rotate(5deg);
  }
  100% {
    transform: rotate(-5deg);
  }
}
.switchTab {
  width: 400px;
  height: 80px;
  position: absolute;
  right: 0;
  left: 0;
  bottom: 100px;
  display: flex;
  margin: 0 auto;
  ul {
    width: 100%;
    height: 100%;
    background-color: #fff;
    border-radius: 5px;
    display: flex;
    align-items: center;
    li {
      float: left;
      width: 80px;
      display: flex;
      flex-direction: column;
      align-items: center;
      cursor: pointer;
      .icon {
        font-size: 35px;
        font-weight: 700;
        transform: translateY(10px);
        transition: 0.3s;
        z-index: 3;
      }
      .text {
        font-size: 15px;
        font-weight: 700;
        transform: translateY(30px);
        transition: 0.3s;
        opacity: 0;
      }
    }
    li:hover {
      .icon {
        transform: rotate(5deg);
        animation: shake 0.5s infinite linear;
      }
    }
    li.active:hover {
      .icon {
        animation: none;
      }
    }
    li.active {
      .icon {
        font-size: 35px;
        font-weight: 700;
        transform: translateY(-30px);
      }
      .text {
        font-size: 15px;
        font-weight: 700;
        transform: translateY(0px);
        opacity: 0.8;
      }
    }
    .background {
      width: 60px;
      height: 60px;
      --color: v-bind(FDATA.color);
      background-color: var(--color);
      position: absolute;
      top: -35%;
      left: 9px;
      border-radius: 50%;
      border: 5px solid #333;
      box-sizing: border-box;
      transition: 0.3s;
    }
    .background:before {
      content: "";
      width: 12px;
      height: 12px;
      position: absolute;
      left: -15px;
      top: 46%;
      border-top-right-radius: 100%;
      box-shadow: 2px -2px 0 1px #333;
    }
    .background:after {
      content: "";
      width: 12px;
      height: 12px;
      position: absolute;
      right: -15px;
      top: 46%;
      border-top-left-radius: 100%;
      box-shadow: -1px -4px 0 1px #333;
    }
  }
}
.container li:nth-child(1).active ~ .background {
  transform: translateX(80px * 0);
}
.container li:nth-child(2).active ~ .background {
  transform: translateX(80px * 1);
}
.container li:nth-child(3).active ~ .background {
  transform: translateX(80px * 2);
}
.container li:nth-child(4).active ~ .background {
  transform: translateX(80px * 3);
}
.container li:nth-child(5).active ~ .background {
  transform: translateX(80px * 4);
}
</style>

在父组件中引入并传参

import switchTab from "@/components/switchTab.vue";

<switchTab :tabList="tabList" :num="3" :color="'#ccc'"></switchTab>  
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值