383 lines
7.7 KiB
Vue
383 lines
7.7 KiB
Vue
<template>
|
||
<view
|
||
class="tui-tabs-view"
|
||
:class="[
|
||
isFixed ? 'tui-tabs-fixed' : 'tui-tabs-relative',
|
||
unlined ? 'tui-unlined' : '',
|
||
]"
|
||
:style="{
|
||
width: tabsWidth + 'px',
|
||
height: height + 'rpx',
|
||
padding: `0 ${padding}rpx`,
|
||
background: backgroundColor,
|
||
top: isFixed ? top + 'px' : 'auto',
|
||
zIndex: isFixed ? zIndex : 'auto',
|
||
}"
|
||
v-if="tabsWidth > 0"
|
||
>
|
||
<view
|
||
v-for="(item, index) in tabs"
|
||
:key="index"
|
||
:class="['tui-tabs-item', { tui__tab_current: currentTab == index }]"
|
||
:style="{ width: getItemWidth, height: height + 'rpx' }"
|
||
@tap.stop="swichTabs(index)"
|
||
>
|
||
<view
|
||
class="tui-tabs-title"
|
||
:class="{ 'tui-tabs-disabled': item.disabled }"
|
||
:style="{
|
||
color: currentTab == index ? getSelectedColor : color,
|
||
fontSize: size + 'rpx',
|
||
fontWeight: bold && currentTab == index ? 'bold' : 'normal',
|
||
transform: `scale(${currentTab == index ? scale : 1})`,
|
||
}"
|
||
>
|
||
{{ item[field] }}
|
||
<view
|
||
:class="[item.isDot ? 'tui-badge__dot' : 'tui-tabs__badge']"
|
||
:style="{ color: badgeColor, backgroundColor: getBadgeBgColor }"
|
||
v-if="item[badgeField] || item.isDot"
|
||
>
|
||
{{ item.isDot ? "" : item[badgeField] }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view
|
||
v-if="isSlider"
|
||
class="tui-tabs-slider"
|
||
:style="{
|
||
transform: 'translateX(' + scrollLeft + 'px)',
|
||
width: sliderWidth + 'rpx',
|
||
height: sliderHeight + 'rpx',
|
||
borderRadius: sliderRadius,
|
||
bottom: bottom,
|
||
background: getSliderBgColor,
|
||
marginBottom: bottom == '50%' ? '-' + sliderHeight / 2 + 'rpx' : 0,
|
||
}"
|
||
></view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: "tuiTabs",
|
||
emits: ["change"],
|
||
props: {
|
||
//标签页
|
||
tabs: {
|
||
type: Array,
|
||
default() {
|
||
return [];
|
||
},
|
||
},
|
||
//显示文本字段名称
|
||
field: {
|
||
type: String,
|
||
default: "name",
|
||
},
|
||
badgeField: {
|
||
type: String,
|
||
default: "num",
|
||
},
|
||
//tabs宽度,不传值则默认使用windowWidth,单位px
|
||
width: {
|
||
type: [Number, String],
|
||
default: 0,
|
||
},
|
||
//rpx
|
||
height: {
|
||
type: Number,
|
||
default: 80,
|
||
},
|
||
//rpx 只对左右padding起作用,上下为0
|
||
padding: {
|
||
type: Number,
|
||
default: 30,
|
||
},
|
||
//背景色
|
||
backgroundColor: {
|
||
type: String,
|
||
default: "#FFFFFF",
|
||
},
|
||
//是否固定
|
||
isFixed: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
//px
|
||
top: {
|
||
type: Number,
|
||
// #ifndef H5
|
||
default: 0,
|
||
// #endif
|
||
// #ifdef H5
|
||
default: 44,
|
||
// #endif
|
||
},
|
||
//是否去掉底部线条
|
||
unlined: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
//当前选项卡
|
||
currentTab: {
|
||
type: Number,
|
||
default: 0,
|
||
},
|
||
isSlider: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
//滑块宽度
|
||
sliderWidth: {
|
||
type: Number,
|
||
default: 68,
|
||
},
|
||
//滑块高度
|
||
sliderHeight: {
|
||
type: Number,
|
||
default: 6,
|
||
},
|
||
//滑块背景颜色
|
||
sliderBgColor: {
|
||
type: String,
|
||
default: "",
|
||
},
|
||
sliderRadius: {
|
||
type: String,
|
||
default: "50rpx",
|
||
},
|
||
//滑块bottom
|
||
bottom: {
|
||
type: String,
|
||
default: "0",
|
||
},
|
||
//标签页宽度
|
||
itemWidth: {
|
||
type: String,
|
||
default: "",
|
||
},
|
||
//字体颜色
|
||
color: {
|
||
type: String,
|
||
default: "#666",
|
||
},
|
||
//选中后字体颜色
|
||
selectedColor: {
|
||
type: String,
|
||
default: "",
|
||
},
|
||
//字体大小
|
||
size: {
|
||
type: Number,
|
||
default: 28,
|
||
},
|
||
//选中后 是否加粗 ,未选中则无效
|
||
bold: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
//2.3.0+
|
||
scale: {
|
||
type: [Number, String],
|
||
default: 1,
|
||
},
|
||
//角标字体颜色
|
||
badgeColor: {
|
||
type: String,
|
||
default: "#fff",
|
||
},
|
||
//角标背景颜色
|
||
badgeBgColor: {
|
||
type: String,
|
||
default: "",
|
||
},
|
||
zIndex: {
|
||
type: [Number, String],
|
||
default: 996,
|
||
},
|
||
},
|
||
watch: {
|
||
currentTab() {
|
||
this.checkCor();
|
||
},
|
||
tabs() {
|
||
this.checkCor();
|
||
},
|
||
width(val) {
|
||
this.tabsWidth = val;
|
||
this.checkCor();
|
||
},
|
||
},
|
||
computed: {
|
||
getItemWidth() {
|
||
let width = 100 / (this.tabs.length || 4) + "%";
|
||
return this.itemWidth ? this.itemWidth : width;
|
||
},
|
||
getSliderBgColor() {
|
||
return (
|
||
this.sliderBgColor ||
|
||
(uni && uni.$tui && uni.$tui.color.primary) ||
|
||
"#5677fc"
|
||
);
|
||
},
|
||
getSelectedColor() {
|
||
return (
|
||
this.selectedColor ||
|
||
(uni && uni.$tui && uni.$tui.color.primary) ||
|
||
"#5677fc"
|
||
);
|
||
},
|
||
getBadgeBgColor() {
|
||
return (
|
||
this.badgeBgColor ||
|
||
(uni && uni.$tui && uni.$tui.color.pink) ||
|
||
"#f74d54"
|
||
);
|
||
},
|
||
},
|
||
created() {
|
||
// 高度自适应
|
||
setTimeout(() => {
|
||
uni.getSystemInfo({
|
||
success: (res) => {
|
||
this.winWidth = res.windowWidth;
|
||
this.tabsWidth = this.width == 0 ? this.winWidth : Number(this.width);
|
||
this.checkCor();
|
||
},
|
||
});
|
||
}, 0);
|
||
},
|
||
data() {
|
||
return {
|
||
winWidth: 0,
|
||
tabsWidth: 0,
|
||
scrollLeft: 0,
|
||
};
|
||
},
|
||
methods: {
|
||
checkCor: function () {
|
||
let tabsNum = this.tabs.length;
|
||
let padding = uni.upx2px(Number(this.padding));
|
||
let width = this.tabsWidth - padding * 2;
|
||
let left =
|
||
(width / tabsNum - uni.upx2px(Number(this.sliderWidth))) / 2 + padding;
|
||
let scrollLeft = left;
|
||
if (this.currentTab > 0) {
|
||
scrollLeft = scrollLeft + (width / tabsNum) * this.currentTab;
|
||
}
|
||
this.scrollLeft = scrollLeft;
|
||
},
|
||
// 点击标题切换当前页时改变样式
|
||
swichTabs: function (index) {
|
||
let item = this.tabs[index];
|
||
if (item && item.disabled) return;
|
||
if (this.currentTab == index) {
|
||
return false;
|
||
} else {
|
||
this.$emit("change", {
|
||
index: Number(index),
|
||
item: item,
|
||
});
|
||
}
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.tui-tabs-view {
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.tui-tabs-relative {
|
||
position: relative;
|
||
}
|
||
|
||
.tui-tabs-fixed {
|
||
position: fixed;
|
||
left: 0;
|
||
}
|
||
|
||
.tui-tabs-fixed::before,
|
||
.tui-tabs-relative::before {
|
||
content: "";
|
||
position: absolute;
|
||
border-bottom: 1rpx solid #eaeef1;
|
||
-webkit-transform: scaleY(0.5) translateZ(0);
|
||
transform: scaleY(0.5) translateZ(0);
|
||
transform-origin: 0 100%;
|
||
bottom: 0;
|
||
right: 0;
|
||
left: 0;
|
||
}
|
||
|
||
.tui-unlined::before {
|
||
border-bottom: 0 !important;
|
||
}
|
||
|
||
.tui-tabs-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
overflow: visible;
|
||
/* #ifdef H5 */
|
||
cursor: pointer;
|
||
/* #endif */
|
||
}
|
||
|
||
.tui-tabs-disabled {
|
||
opacity: 0.6;
|
||
}
|
||
|
||
.tui-tabs-title {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
z-index: 3;
|
||
overflow: visible;
|
||
transition: all 0.15s ease-in-out;
|
||
}
|
||
|
||
.tui-tabs-slider {
|
||
position: absolute;
|
||
left: 0;
|
||
transition: all 0.3s ease-in-out;
|
||
z-index: 1;
|
||
transform-style: preserve-3d;
|
||
}
|
||
|
||
.tui-tabs__badge {
|
||
position: absolute;
|
||
font-size: 24rpx;
|
||
height: 32rpx;
|
||
min-width: 20rpx;
|
||
padding: 0 6rpx;
|
||
border-radius: 40rpx;
|
||
right: 0;
|
||
top: 0;
|
||
transform: translate(88%, -50%);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
z-index: 4;
|
||
font-weight: normal !important;
|
||
}
|
||
|
||
.tui-badge__dot {
|
||
position: absolute;
|
||
height: 16rpx;
|
||
width: 16rpx;
|
||
border-radius: 50%;
|
||
right: -10rpx;
|
||
top: -10rpx;
|
||
z-index: 4;
|
||
}
|
||
</style>
|