<template>
<view class="u-subsection" :style="[subsectionStyle]">
<view
class="u-item u-line-1"
:style="[itemStyle(index)]"
@tap="click(index)"
:class="[noBorderRight(index), 'u-item-' + index]"
v-for="(item, index) in listInfo"
:key="index"
>
<view :style="[textStyle(index)]" class="u-item-text u-line-1">{{ item.name }}</view>
</view>
<view class="u-item-bg" :style="[itemBarStyle]"></view>
</view>
</template>
<script>
export default {
name: 'u-subsection',
props: {
list: {
type: Array,
default() {
return []
}
},
current: {
type: [Number, String],
default: 0
},
activeColor: {
type: String,
default: '#303133'
},
inactiveColor: {
type: String,
default: '#606266'
},
mode: {
type: String,
default: 'button'
},
fontSize: {
type: [Number, String],
default: 14
},
animation: {
type: Boolean,
default: true
},
height: {
type: [Number, String],
default: 35
},
bold: {
type: Boolean,
default: true
},
bgColor: {
type: String,
default: '#eeeeef'
},
buttonColor: {
type: String,
default: '#ffffff'
},
vibrateShort: {
type: Boolean,
default: false
}
},
data() {
return {
listInfo: [],
itemBgStyle: {
width: 0,
left: 0,
backgroundColor: '#ffffff',
height: '100%',
transition: ''
},
currentIndex: this.current,
buttonPadding: 3,
borderRadius: 5,
firstTimeVibrateShort: true
}
},
watch: {
current: {
immediate: true,
handler(nVal) {
this.currentIndex = nVal
this.changeSectionStatus(nVal)
}
}
},
created() {
this.listInfo = this.list.map((val, index) => {
if (typeof val != 'object') {
let obj = {
width: 0,
name: val
}
return obj
} else {
val.width = 0
return val
}
})
},
computed: {
noBorderRight() {
return index => {
if (this.mode != 'subsection') return
let classs = ''
if (index < this.list.length - 1) classs += ' u-none-border-right'
if (index == 0) classs += ' u-item-first'
if (index == this.list.length - 1) classs += ' u-item-last'
return classs
}
},
textStyle() {
return index => {
let style = {}
if (this.mode == 'subsection') {
if (index == this.currentIndex) {
style.color = '#ffffff'
} else {
style.color = this.activeColor
}
} else {
if (index == this.currentIndex) {
style.color = this.activeColor
} else {
style.color = this.inactiveColor
}
}
if (index == this.currentIndex && this.bold) style.fontWeight = 'bold'
style.fontSize = this.fontSize + 'rpx'
return style
}
},
itemStyle() {
return index => {
let style = {}
if (this.mode == 'subsection') {
style.borderColor = this.activeColor
style.borderWidth = '1px'
style.borderStyle = 'solid'
}
return style
}
},
subsectionStyle() {
let style = {}
style.height = uni.upx2px(this.height) + 'px'
if (this.mode == 'button') {
style.backgroundColor = this.bgColor
style.padding = `${this.buttonPadding}px`
style.borderRadius = `${this.borderRadius}px`
}
return style
},
itemBarStyle() {
let style = {}
style.backgroundColor = this.activeColor
style.zIndex = 1
if (this.mode == 'button') {
style.backgroundColor = this.buttonColor
style.borderRadius = `${this.borderRadius}px`
style.bottom = `${this.buttonPadding}px`
style.height = uni.upx2px(this.height) - this.buttonPadding * 2 + 'px'
style.zIndex = 0
}
return Object.assign(this.itemBgStyle, style)
}
},
mounted() {
setTimeout(() => {
this.getTabsInfo()
}, 10)
},
methods: {
changeSectionStatus(nVal) {
if (this.mode == 'subsection') {
if (nVal == this.list.length - 1) {
this.itemBgStyle.borderRadius = `0 ${this.buttonPadding}px ${this.buttonPadding}px 0`
}
if (nVal == 0) {
this.itemBgStyle.borderRadius = `${this.buttonPadding}px 0 0 ${this.buttonPadding}px`
}
if (nVal > 0 && nVal < this.list.length - 1) {
this.itemBgStyle.borderRadius = '0'
}
}
setTimeout(() => {
this.itemBgLeft()
}, 10)
if (this.vibrateShort && !this.firstTimeVibrateShort) {
uni.vibrateShort()
}
this.firstTimeVibrateShort = false
},
click(index) {
if (index == this.currentIndex) return
this.currentIndex = index
this.changeSectionStatus(index)
this.$emit('change', Number(index))
},
getTabsInfo() {
let view = uni.createSelectorQuery().in(this)
for (let i = 0; i < this.list.length; i++) {
view.select('.u-item-' + i).boundingClientRect()
}
view.exec(res => {
if (!res.length) {
setTimeout(() => {
this.getTabsInfo()
return
}, 10)
}
res.map((val, index) => {
this.listInfo[index].width = val.width
})
if (this.mode == 'subsection') {
this.itemBgStyle.width = this.listInfo[0].width + 'px'
} else if (this.mode == 'button') {
this.itemBgStyle.width = this.listInfo[0].width + 'px'
}
this.itemBgLeft()
})
},
itemBgLeft() {
if (this.animation) {
this.itemBgStyle.transition = 'all 0.35s'
} else {
this.itemBgStyle.transition = 'all 0s'
}
let left = 0
this.listInfo.map((val, index) => {
if (index < this.currentIndex) left += val.width
})
if (this.mode == 'subsection') {
this.itemBgStyle.left = left + 'px'
} else if (this.mode == 'button') {
this.itemBgStyle.left = left + this.buttonPadding + 'px'
}
}
}
}
</script>
<style lang="scss" scoped>
@import '../../libs/css/style.components.scss';
.u-subsection {
display: flex;
align-items: center;
overflow: hidden;
position: relative;
}
.u-item {
flex: 1;
text-align: center;
font-size: 13rpx;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: $u-main-color;
display: inline-flex;
padding: 0 6rpx;
}
.u-item-bg {
background-color: $u-type-primary;
position: absolute;
z-index: -1;
}
.u-none-border-right {
border-right: none !important;
}
.u-item-first {
border-top-left-radius: 8rpx;
border-bottom-left-radius: 8rpx;
}
.u-item-last {
border-top-right-radius: 8rpx;
border-bottom-right-radius: 8rpx;
}
.u-item-text {
transition: all 0.35s;
color: $u-main-color;
display: flex;
align-items: center;
position: relative;
z-index: 99;
}
</style>