修复分段器动态赋值不生效的bug

This commit is contained in:
qixv-0506
2023-08-08 21:40:14 +08:00
parent 9578de3358
commit 712d73d2b0

View File

@@ -1,410 +1,414 @@
<template> <template>
<view <view class="tn-subsection-class tn-subsection" :class="[subsectionBackgroundColorClass]"
class="tn-subsection-class tn-subsection" :style="[subsectionStyle]">
:class="[subsectionBackgroundColorClass]" <!-- 滑块 -->
:style="[subsectionStyle]" <block v-for="(item, index) in listInfo" :key="index">
> <view class="tn-subsection__item tn-text-ellipsis" :class="[
<!-- 滑块 -->
<block v-for="(item, index) in listInfo" :key="index">
<view
class="tn-subsection__item tn-text-ellipsis"
:class="[
'section-item-' + index, 'section-item-' + index,
noBorderRight(index) noBorderRight(index)
]" ]" :style="[itemStyle(index)]" @tap="click(index)">
:style="[itemStyle(index)]" <view class="tn-subsection__item--text tn-text-ellipsis" :style="[textStyle(index)]">
@tap="click(index)" {{ item.name }}
> </view>
<view class="tn-subsection__item--text tn-text-ellipsis" :style="[textStyle(index)]"> </view>
{{ item.name }} </block>
</view> <!-- 背景 -->
</view> <view class="tn-subsection__bg" :class="[itemBarClass]" :style="[itemBarStyle]"></view>
</block> </view>
<!-- 背景 -->
<view
class="tn-subsection__bg"
:class="[itemBarClass]"
:style="[itemBarStyle]"
></view>
</view>
</template> </template>
<script> <script>
import componentsColorMixin from '../../libs/mixin/components_color.js' import componentsColorMixin from '../../libs/mixin/components_color.js'
export default { export default {
mixins: [componentsColorMixin], mixins: [componentsColorMixin],
name: 'tn-subsection', name: 'tn-subsection',
props: { props: {
// 模式选择 // 模式选择
// button 按钮模式 subsection 分段模式 // button 按钮模式 subsection 分段模式
mode: { mode: {
type: String, type: String,
default: 'subsection' default: 'subsection'
}, },
// 组件高度 // 组件高度
height: { height: {
type: Number, type: Number,
default: 60 default: 60
}, },
// tab的数据 // tab的数据
list: { list: {
type: Array, type: Array,
default() { default () {
return [] return []
} }
}, },
// 当前活动tab的index // 当前活动tab的index
current: { current: {
type: [Number, String], type: [Number, String],
default: 0 default: 0
}, },
// 激活时的字体颜色 // 激活时的字体颜色
activeColor: { activeColor: {
type: String, type: String,
default: '#FFFFFF' default: '#FFFFFF'
}, },
// 未激活时的字体颜色 // 未激活时的字体颜色
inactiveColor: { inactiveColor: {
type: String, type: String,
default: '#AAAAAA' default: '#AAAAAA'
}, },
// 激活tab的字体是否加粗 // 激活tab的字体是否加粗
bold: { bold: {
type: Boolean, type: Boolean,
default: false default: false
}, },
backgroundColor: { backgroundColor: {
type: String, type: String,
default: '#F4F4F4' default: '#F4F4F4'
}, },
// 滑块的颜色 // 滑块的颜色
buttonColor: { buttonColor: {
type: String, type: String,
default: '#01BEFF' default: '#01BEFF'
}, },
// 当mode为button时生效圆角的值单位rpx // 当mode为button时生效圆角的值单位rpx
borderRadius: { borderRadius: {
type: Number, type: Number,
default: 10 default: 10
}, },
// 是否开启动画 // 是否开启动画
animation: { animation: {
type: Boolean, type: Boolean,
default: true default: true
}, },
// 动画类型 // 动画类型
// cubic-bezier -> 贝塞尔曲线 // cubic-bezier -> 贝塞尔曲线
animationType: { animationType: {
type: String, type: String,
default: '' default: ''
}, },
// 滑动滑块的是否,是否触发震动 // 滑动滑块的是否,是否触发震动
vibrateShort: { vibrateShort: {
type: Boolean, type: Boolean,
default: false default: false
} }
}, },
data() { data() {
return { return {
// 列表数据 // 列表数据
listInfo: [], listInfo: [],
// 子元素的背景样式 // 子元素的背景样式
itemBgStyle: { itemBgStyle: {
width: 0, width: 0,
left: 0, left: 0,
backgroundColor: '#ffffff', backgroundColor: '#ffffff',
height: '100%' height: '100%'
}, },
// 当前选中的滑块 // 当前选中的滑块
currentIndex: this.current, currentIndex: this.current,
buttonPadding: 3, buttonPadding: 3,
// 组件初始化的是否current变换不应该震动 // 组件初始化的是否current变换不应该震动
firstVibrateShort: true firstVibrateShort: true
} }
}, },
watch: { watch: {
current: { list: {
handler(val) { handler(val) {
this.currentIndex = val this.listInfo = val.map((item, index) => {
this.changeSectionStatus(val) if (typeof item !== 'object') {
}, let obj = {
immediate: true width: 0,
} name: item
}, }
created() { return obj
// 将list的数据传入listInfo数组 } else {
// 接受直接数组形式,或者数组元素为对象的形式,如:['开启', '关闭'],或者[{name: '开启'}, {name: '关闭'}] item.width = 0
this.listInfo = this.list.map((item, index) => { return obj
if (typeof item !== 'object') { }
let obj = { })
width: 0, },
name: item immediate: true,
} deep: true
return obj },
} else { current: {
item.width = 0 handler(val) {
return obj this.currentIndex = val
} this.changeSectionStatus(val)
}) },
}, immediate: true
computed: { }
// 设置mode=subsection时滑块没有样式 },
noBorderRight() { created() {
return index => { // 将list的数据传入listInfo数组
if (this.mode !== 'subsection') return // 接受直接数组形式,或者数组元素为对象的形式,如:['开启', '关闭'],或者[{name: '开启'}, {name: '关闭'}]
let clazz = '' this.listInfo = this.list.map((item, index) => {
// 不显示右边的边距 if (typeof item !== 'object') {
if (index < this.list.length - 1) clazz += ' tn-subsection__item--none-border-right' let obj = {
// 显示整个组件的左右边圆角 width: 0,
if (index === 0) clazz += ' tn-subsection__item--first' name: item
if (index === this.list.length - 1) clazz += ' tn-subsection__item--last' }
return clazz return obj
} } else {
}, item.width = 0
// 文字的样式 return obj
textStyle() { }
return index => { })
let style = {} },
// 设置字体颜色 computed: {
if (index === this.currentIndex) { // 设置mode=subsection时滑块没有样式
style.color = this.activeColor noBorderRight() {
} else { return index => {
style.color = this.inactiveColor if (this.mode !== 'subsection') return
} let clazz = ''
// 字体加粗 // 不显示右边的边距
if (index === this.currentIndex && this.bold) style.fontWeight = 'bold' if (index < this.list.length - 1) clazz += ' tn-subsection__item--none-border-right'
// 文字大小 // 显示整个组件的左右边圆角
style.fontSize = (this.fontSize || 26) + this.fontUnit if (index === 0) clazz += ' tn-subsection__item--first'
return style if (index === this.list.length - 1) clazz += ' tn-subsection__item--last'
} return clazz
}, }
// 每个分段器item的样式 },
itemStyle() { // 文字的样式
return index => { textStyle() {
let style = {} return index => {
if (this.fontSizeStyle) { let style = {}
style.fontSize = this.fontSizeStyle // 设置字体颜色
} if (index === this.currentIndex) {
if (this.mode === 'subsection') { style.color = this.activeColor
// 设置border的样式 } else {
style.borderColor = this.buttonColor style.color = this.inactiveColor
style.borderWidth = '1rpx' }
style.borderStyle = 'solid' // 字体加粗
} if (index === this.currentIndex && this.bold) style.fontWeight = 'bold'
return style // 文字大小
} style.fontSize = (this.fontSize || 26) + this.fontUnit
}, return style
// mode = button时设置外层view的样式 }
subsectionStyle() { },
let style = {} // 每个分段器item的样式
style.height = this.height + 'rpx' itemStyle() {
if (this.mode === 'button') { return index => {
style.backgroundColor = this.backgroundColorStyle let style = {}
style.padding = `${this.buttonPadding}px` if (this.fontSizeStyle) {
style.borderRadius = `${this.borderRadius}rpx` style.fontSize = this.fontSizeStyle
} }
return style if (this.mode === 'subsection') {
}, // 设置border的样式
// mode = button时设置外层view的背景class style.borderColor = this.buttonColor
subsectionBackgroundColorClass() { style.borderWidth = '1rpx'
let clazz = '' style.borderStyle = 'solid'
if (this.mode === 'button' && this.backgroundColorClass) { }
clazz = this.backgroundColorClass return style
} }
return clazz },
}, // mode = button时设置外层view的样式
itemBarClass() { subsectionStyle() {
let clazz = '' let style = {}
const buttonBgClass = this.$tn.color.getBackgroundColorInternalClass(this.buttonColor) style.height = this.height + 'rpx'
if (this.animation) { if (this.mode === 'button') {
clazz += ' tn-subsection__bg__animation' style.backgroundColor = this.backgroundColorStyle
if (this.animationType) { style.padding = `${this.buttonPadding}px`
clazz += ` tn-subsection__bg__animation--${this.animationType}` style.borderRadius = `${this.borderRadius}rpx`
} }
} return style
if (buttonBgClass) { },
clazz += ` ${buttonBgClass}` // mode = button时设置外层view的背景class
} subsectionBackgroundColorClass() {
return clazz let clazz = ''
}, if (this.mode === 'button' && this.backgroundColorClass) {
// 滑块样式 clazz = this.backgroundColorClass
itemBarStyle() { }
let style = {} return clazz
const buttonBgStyle = this.$tn.color.getBackgroundColorStyle(this.buttonColor) },
if (buttonBgStyle) { itemBarClass() {
style.backgroundColor = this.buttonColor let clazz = ''
} const buttonBgClass = this.$tn.color.getBackgroundColorInternalClass(this.buttonColor)
style.zIndex = 1 if (this.animation) {
if (this.mode === 'button') { clazz += ' tn-subsection__bg__animation'
style.borderRadius = `${this.borderRadius}rpx` if (this.animationType) {
style.bottom = `${this.buttonPadding}px` clazz += ` tn-subsection__bg__animation--${this.animationType}`
style.height = (this.height - (this.buttonPadding * 4)) + 'rpx' }
style.zIndex = 0 }
} if (buttonBgClass) {
return Object.assign(this.itemBgStyle, style) clazz += ` ${buttonBgClass}`
} }
}, return clazz
mounted() { },
// 等待加载组件完成 // 滑块样式
setTimeout(() => { itemBarStyle() {
this.getTabsInfo() let style = {}
}, 10) const buttonBgStyle = this.$tn.color.getBackgroundColorStyle(this.buttonColor)
}, if (buttonBgStyle) {
methods: { style.backgroundColor = this.buttonColor
// 改变滑块样式 }
changeSectionStatus(val) { style.zIndex = 1
if (this.mode === 'subsection') { if (this.mode === 'button') {
// 根据滑块在最左和最右时,显示对应的圆角 style.borderRadius = `${this.borderRadius}rpx`
if (val === this.list.length - 1) { style.bottom = `${this.buttonPadding}px`
this.itemBgStyle.borderRadius = `0 ${this.buttonPadding}px ${this.buttonPadding}px 0` style.height = (this.height - (this.buttonPadding * 4)) + 'rpx'
} style.zIndex = 0
if (val === 0) { }
this.itemBgStyle.borderRadius = `${this.buttonPadding}px 0 0 ${this.buttonPadding}px` return Object.assign(this.itemBgStyle, style)
} }
if (val > 0 && val < this.list.length - 1) { },
this.itemBgStyle.borderRadius = '0' mounted() {
} // 等待加载组件完成
} setTimeout(() => {
// 更新滑块的位置 this.getTabsInfo()
setTimeout(() => { }, 10)
this.itemBgLeft() },
}, 10) methods: {
if (this.vibrateShort && !this.firstVibrateShort) { // 改变滑块样式
// 使手机产生短促震动微信小程序有效APP(HX 2.6.8)和H5无效 changeSectionStatus(val) {
// #ifndef H5 if (this.mode === 'subsection') {
uni.vibrateShort(); // 根据滑块在最左和最右时,显示对应的圆角
// #endif if (val === this.list.length - 1) {
} this.itemBgStyle.borderRadius = `0 ${this.buttonPadding}px ${this.buttonPadding}px 0`
this.firstVibrateShort = false }
}, if (val === 0) {
// 获取各个tab的节点信息 this.itemBgStyle.borderRadius = `${this.buttonPadding}px 0 0 ${this.buttonPadding}px`
getTabsInfo() { }
let view = uni.createSelectorQuery().in(this) if (val > 0 && val < this.list.length - 1) {
for (let i = 0; i < this.list.length; i++) { this.itemBgStyle.borderRadius = '0'
view.select('.section-item-' + i).boundingClientRect() }
} }
view.exec(res => { // 更新滑块的位置
// 如果没有获取到,则重新获取 setTimeout(() => {
if (!res.length) { this.itemBgLeft()
setTimeout(() => { }, 10)
this.getTabsInfo() if (this.vibrateShort && !this.firstVibrateShort) {
return // 使手机产生短促震动微信小程序有效APP(HX 2.6.8)和H5无效
}, 10) // #ifndef H5
} uni.vibrateShort();
// 将每个分段器的宽度放入listInfo中 // #endif
res.map((item, index) => { }
this.listInfo[index].width = item.width this.firstVibrateShort = false
}) },
// 初始化滑块的宽度 // 获取各个tab的节点信息
if (this.mode === 'subsection') { getTabsInfo() {
this.itemBgStyle.width = this.listInfo[0].width + 'px' let view = uni.createSelectorQuery().in(this)
} else if (this.mode === 'button') { for (let i = 0; i < this.list.length; i++) {
this.itemBgStyle.width = this.listInfo[0].width + 'px' view.select('.section-item-' + i).boundingClientRect()
} }
view.exec(res => {
// 初始化滑块的位置 // 如果没有获取到,则重新获取
this.itemBgLeft() if (!res.length) {
}) setTimeout(() => {
}, this.getTabsInfo()
// 设置滑块的位置 return
itemBgLeft() { }, 10)
let left = 0 }
// 计算当前活跃item到组件左边的距离 // 将每个分段器的宽度放入listInfo中
this.listInfo.map((item, index) => { res.map((item, index) => {
if (index < this.currentIndex) left += item.width this.listInfo[index].width = item.width
}) })
// 根据不同的模式,计算滑块的位置 // 初始化滑块的宽度
if (this.mode === 'subsection') { if (this.mode === 'subsection') {
this.itemBgStyle.left = left + 'px' this.itemBgStyle.width = this.listInfo[0].width + 'px'
} else if (this.mode === 'button') { } else if (this.mode === 'button') {
this.itemBgStyle.left = left + this.buttonPadding + 'px' this.itemBgStyle.width = this.listInfo[0].width + 'px'
} }
},
// 初始化滑块的位置
// 点击事件 this.itemBgLeft()
click(index) { })
// 不允许点击当前激活的选项 },
if (index === this.currentIndex) return // 设置滑块的位置
this.currentIndex = index itemBgLeft() {
this.changeSectionStatus(index) let left = 0
this.$emit('change', { // 计算当前活跃item到组件左边的距离
index: Number(index), this.listInfo.map((item, index) => {
name: this.listInfo[index]['name'] if (index < this.currentIndex) left += item.width
}) })
} // 根据不同的模式,计算滑块的位置
} if (this.mode === 'subsection') {
} this.itemBgStyle.left = left + 'px'
} else if (this.mode === 'button') {
this.itemBgStyle.left = left + this.buttonPadding + 'px'
}
},
// 点击事件
click(index) {
// 不允许点击当前激活的选项
if (index === this.currentIndex) return
this.currentIndex = index
this.changeSectionStatus(index)
this.$emit('change', {
index: Number(index),
name: this.listInfo[index]['name']
})
}
}
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.tn-subsection {
.tn-subsection { /* #ifndef APP-PLUS */
/* #ifndef APP-PLUS */ display: flex;
display: flex; flex-direction: row;
flex-direction: row; /* #endif */
/* #endif */ align-items: center;
align-items: center; overflow: hidden;
overflow: hidden; position: relative;
position: relative;
&__item {
&__item { /* #ifndef APP-PLUS */
/* #ifndef APP-PLUS */ display: flex;
display: flex; flex-direction: row;
flex-direction: row; /* #endif */
/* #endif */ flex: 1;
flex: 1; text-align: center;
text-align: center; font-size: 26rpx;
font-size: 26rpx; height: 100%;
height: 100%; align-items: center;
align-items: center; justify-content: center;
justify-content: center; color: #FFFFFF;
color: #FFFFFF; padding: 0 6rpx;
padding: 0 6rpx;
&--text {
&--text { transition: all 0.3s;
transition: all 0.3s; color: #FFFFFF;
color: #FFFFFF; /* #ifndef APP-PLUS */
/* #ifndef APP-PLUS */ display: flex;
display: flex; flex-direction: row;
flex-direction: row; /* #endif */
/* #endif */ align-items: center;
align-items: center; position: relative;
position: relative; z-index: 3;
z-index: 3; }
}
&--first {
&--first { border-top-left-radius: 8rpx;
border-top-left-radius: 8rpx; border-bottom-left-radius: 8rpx;
border-bottom-left-radius: 8rpx; }
}
&--last {
&--last { border-top-right-radius: 8rpx;
border-top-right-radius: 8rpx; border-bottom-right-radius: 8rpx;
border-bottom-right-radius: 8rpx; }
}
&--none-border-right {
&--none-border-right { border-right: none !important;
border-right: none !important; }
} }
}
&__bg {
&__bg { background-color: $tn-main-color;
background-color: $tn-main-color; position: absolute;
position: absolute; z-index: -1;
z-index: -1; transition-property: all;
transition-property: all; transition-duration: 0s;
transition-duration: 0s; transition-timing-function: linear;
transition-timing-function: linear;
&__animation {
&__animation { transition-duration: 0.25s !important;
transition-duration: 0.25s !important;
&--cubic-bezier {
&--cubic-bezier { transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55) !important;
transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55) !important; }
} }
} }
} }
} </style>
</style>