vue3 封装简单的 tabs 切换组件

背景:公司项目要求全部换成 vue3 ,而且也没有应用像 element-ui 一类的UI组件,用到的公共组件都是根据项目需求封装的,下面是使用vue3实现简单的tabs组件,我只是把代码分享出来,实现思路如果有需要等我项目不忙了在更,希望大家多提些建议,共同学习共同进步。

tab-group.vue

<template>
  <div class="tab-group">
    <!-- tabRef 这块本来是用来实现下划线动态切换特效的,暂时没有写效果 -->
    <div ref="barRef" class="tab-bar" :style="{ width: widthRef + 'px' }"></div>
    <div ref="titsRef" class="tab-header" layout="row" layout-wrap>
      <div
        ref="titRef"
        :class="[{ active: activeKey == item.props.actKey }, 'tab-nav']"
        v-for="(item, index) in tabTitLists"
        :key="item"
        @click="onTabClick($event, item, index)"
      >
        {{ item.props.label }}
      </div>
    </div>
    <div class="tab-panel">
      <slot></slot>
    </div>
  </div>
</template>
<script>
import { ref, onMounted, provide } from "vue";
export default {
  props: {
    defaultKey: {
      type: String,
      default: "1",
    },
  },
  setup(props, context) {
    const tabTitLists = context.slots.default();
    let activeKey = ref(props.defaultKey); //当前key
    provide("activeKey", activeKey);

    const barRef = ref(null);
    const titRef = ref(null);
    let widthRef = ref();
    onMounted(() => {
      // 设置状态线初始化宽度
      widthRef.value = titRef.value.clientWidth;
    });
    function onTabClick(event, tab, index) {
      activeKey.value = tab.props.actKey;
    }
    return {
      tabTitLists,
      barRef,
      titRef,
      widthRef,
      onTabClick,
      activeKey,
    };
  },
};
</script>
<style scoped lang="less">
.tab-group {
  // .tab-bar {
  //   position: absolute;
  //   left: 0;
  //   border-bottom: 2px solid #409eff;
  // }
  .tab-header {
    &:after {
      content: "";
      width: 100%;
      border-bottom: 2px solid #ddd;
    }
  }
  .tab-nav {
    color: #5c5c5c;
    font-size: 14px;
    line-height: 40px;
    display: inline-block;
    margin-right: 3em;
    cursor: pointer;
    border-bottom: 2px solid transparent;
    &.active {
      color: #2f5cd5;
      border-bottom-color: #2f5cd5;
    }
  }
  .tab-panel{
    padding: 15px;
  }
}
</style>

tab-panel.vue

<template>
  <div v-show="actKey == activeKey">
    <slot></slot>
  </div>
</template>
<script>
import { ref, inject } from "vue";
export default {
  props: {
    actKey: {
      type: String,
      default: "1",
    },
    label: {
      type: String,
      default: "全部",
    },
  },

  setup() {
    let activeKey = ref();
    activeKey = inject("activeKey");
    return { activeKey };
  },
};
</script>

应用

<template>
  <div>
    <tab-group defaultKey="1">
      <tab-panel label="进行中" actKey="1">进行中-内容</tab-panel>
      <tab-panel label="已结束" actKey="2">已结束-内容</tab-panel>
      <tab-panel label="全部" actKey="3">全部带-内容</tab-panel>
    </tab-group>
  </div>
</template>
<script>
import tabGroup from "../common/tabs/tab-group.vue";
import tabPanel from "../common/tabs/tab-panel.vue";
export default {
  components: {
    tabPanel,
    tabGroup,
  },
  setup(props, context) {
    return {};
  },
};
</script>
posted @ 2021-07-21 09:10  提子橘子  阅读(3315)  评论(0编辑  收藏  举报