文件夹xxtabs
四个文件 index暴露 render vue添加虚拟节点到插槽(自定义标签结构) tabs选项卡整体 abpaneq切换区
tabs.vue
<template><div class="gnip-tab"><div class="gnip-tab-nav"><divv-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];// 由于直接通过索引修改数组,无法触发响应式,因此需要$setthis.$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() {
//获取插槽内容创建成divreturn 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>