自定义选项卡组件,选项可插槽html

文件夹xxtabs

四个文件 index暴露 render vue添加虚拟节点到插槽(自定义标签结构) tabs选项卡整体 abpaneq切换区

 tabs.vue

<template>
  <div class="gnip-tab">
    <div class="gnip-tab-nav">
      <div
        v-for="(item, index) in tabNavList"
        @click.stop="handleTabNavClick(item, index)"
        :class="['tab-nav-item', item.name == activeName ? 'active' : '']"
        ref="tabNavItemRefs"
      >
        <div class="tab_item" v-if="typeof item.label === 'string'">
          {
   
   { item.text }}
        </div>

        <render v-else :params="item.label"></render>
      </div>
    </div>
    <!-- 滚动滑块 -->

    <div class="tab-content-wrap">
      <slot></slot>
    </div>
  </div>
</template>
<script>
// render组件,label为render函数的时候进行渲染
import Render from "./render";
export default {
  props: {
    // v-model的那项
    value: {
      type: String,
    },
    // 是否显示滑块背景
    showTrackBg: {
      type: Boolean,
      default: false,
    },
    tabWidth: {
      type: String,
      default: "",
    },
  },
  components: {
    Render,
  },
  data() {
    return {
      // tab数组
      tabNavList: [],
      // 当前活跃项
      activeName: "",
      // 滑块的宽度
      trackLineWidht: 0,
      // 当前活跃索引
      currentIndex: 0,
      // 滑块偏移量
      left: 0,
      // 拖拽开始的哪项
      dragOriginItemIndex: null,
      // 拖拽活跃项的索引
      dragStartIndex: null,
    };
  },
  mounted() {
    this.init();
  },
  methods: {
    // 初始化
    init() {
      // 默认当前活跃项为外部v-model的值
      this.activeName = this.value;
    },
    // 设置tab点击栏
    setTabBar(tabsPaneInstance, slotElement) {
      // tab的描述信息可以是字符串也可以是render函数
      const label = tabsPaneInstance.label,
        type = typeof label;
      // 添加到数组项中,根据添加条件渲染
      this.tabNavList.push({
        text: type == "function" ? "" : label,
        renderFun: type == "function" ? label : "",
        name: tabsPaneInstance.name,
        label: slotElement.tab === undefined ? label : slotElement.tab,
      });
    },
    handleTabNavClick(item, index) {
      console.log('name',item,index)
      if (item.name == this.activeName) return;
      // 更新当前活跃项
      this.activeName = item.name;
      // 活跃项的索引
      this.currentIndex = index;
    },

    // 交换tab数据项
    swap(start, end) {
      let startItem = this.tabNavList[start];
      let endItem = this.tabNavList[end];
      // 由于直接通过索引修改数组,无法触发响应式,因此需要$set
      this.$set(this.tabNavList, start, endItem);
      this.$set(this.tabNavList, end, startItem);
    },
  },
};
</script>

<style scoped>
.gnip-tab {
  height: 100%;
  /* width: var(tabWidth); */
  /* width: 200px; */
}
.gnip-tab-nav {
  display: flex;
  position: relative;
}
.tab-nav-item {
  background-color: #074889;

  padding-left: 5px;
  padding-right: 5px;

  line-height: 18px;
  text-align: center;

  height: 24px;

  box-sizing: border-box;

  background: rgb(7, 72, 137);
  border-left: 1px solid rgb(44, 100, 155);
  border-right: 1px solid rgb(44, 100, 155);
  border-bottom: 1px solid rgb(44, 100, 155);
  border-radius: 0px 0px 5px 5px;
}
.tab-nav-item.active {
  background-color: #0078ef;
}
.tab-nav-track {
  width: 100%;
  position: relative;
  height: 2px;
}
.tab-content-wrap{
  height: calc(100% - 24px);
}
.track-line {
  height: 2px;
  background-color: #2d8cf0;
  position: absolute;
  transition: left 0.35s;
}
.tab_item {
}
</style>

tabPane.vue

<template>

    <div class="gnip-tabs-pane" v-if="$parent.activeName === name">
    
      <!-- <transition :name="paneTransitionName"> -->

        <div class="tab-pane-content" >

          <slot name="default"></slot>
          <!-- <slot name="one"></slot> -->
        </div>
      <!-- </transition> -->
    </div>
  </template>
  <script>
  export default {
    props: {

      label: {
        type: [String, Function],
      },
      
      name: {
        type: String,
      },
      disabled: {
        type: Boolean,
        default: false,
      },
    },
    data() {
      return {
        paneTransitionName: "enter-right",
      };
    },
    created() {

      this.$parent.setTabBar(this,this.$slots);

    },
    mounted(){

    },
  };
  </script>
  <style scoped>
  .gnip-tabs-pane {
    height: 100%;
    overflow-x: hidden;
  }
.tab-pane-content{
  height: inherit;
}
  </style>
  

render.js

import { h } from 'vue'

export default {
  data() {
    return {
      msg: 'hello'
    }
  },
  props:{
    params: {
        type: Function,
        default() {
          return function(){};
        },
      },
  },
  render() {
//获取插槽内容创建成div
    return h('div', this.params())
  }
}
  

index.js

import TabPane from "./TabPane.vue";
import Tabs from "./Tabs.vue";
export { Tabs, TabPane };

使用

引入

import { Tabs, TabPane } from "@/components/SreenTabs";

使用

        <Tabs style="margin-left: 10px" :value="logTabName" show-track-bg>
          <TabPane label="日志" name="日志">
         日志文本
          </TabPane>

          <TabPane label="消息" name="消息">
            <template v-slot:tab>
              <n-badge :value="8" :offset="[5, -2]">
                <text style="color: white">消息</text></n-badge
              >
            </template>
           消息文本
          </TabPane>
          <TabPane label="异常" name="异常">
           异常文本
          </TabPane>
        </Tabs>

猜你喜欢

转载自blog.csdn.net/qq_51389137/article/details/131454443