| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 | <template>	<view class="_tab-box" :style="{fontSize: defaultConfig.fontSize + 'rpx', color: defaultConfig.color}">		<scroll-view id="_scroll" :scroll-x="true" class="scroll-view-h" scroll-with-animation :scroll-left="slider.scrollLeft">			<view class="_scroll-content">				<view class="_tab-item-box" :class="[defaultConfig.itemWidth ? '_clamp' : '_flex']">					<block v-for="(item, index) in tabList" :key="index" >						<view 							class="_item"							:id="'_tab_'+index"							:class="{ '_active': tagIndex === index }"							:style="{color: tagIndex == index ? defaultConfig.activeColor : defaultConfig.color, 'width': defaultConfig.itemWidth ? defaultConfig.itemWidth + 'rpx' : ''}"							@click="tabClick(index)">{{ item[defaultConfig.key] || item }}</view>					</block>				</view>				<view class="_underline" :style="{						transform: 'translateX(' + slider.left + 'px)',						width: slider.width + 'px',						height: defaultConfig.underLineHeight + 'rpx',						backgroundColor: defaultConfig.underLineColor,					}" />			</view>		</scroll-view>	</view></template><script>	export default {		name: 'liuyuno-tabs',		props: {			tabData: {				type: Array,				default: () => []			},			activeIndex: {				type: Number,				default: 0			},			config: {				type: Object,				default:() => {					return {}				}			},		},		data() {			return {				tabList: [],				tagIndex: 0,				slider: {					left: 0,					width: 0,					scrollLeft: 0				},				scorll: {},				defaultConfig: {					// 要显示的key					key: 'name',					// 字体大小 rpx					fontSize: 34,					// 字体颜色					color: '#313131',					// 激活字体颜色					activeColor: '#3D93D0',					// item宽度 0为自动					itemWidth: 0,					// 下划线左右边距,文字宽度加边距 rpx					underLinePadding: 10,					// 下划线宽度 rpx  注意:设置了此值 underLinePadding 失效					underLineWidth: 0,					// 下划线高度 rpx					underLineHeight: 4,					// 下划线颜色					underLineColor: '#3D93D0',				},			};		},		watch: {			tabData(value) {				this.updateData();				setTimeout(() => {					this.updateTabWidth();				}, 0);			},			config(value) {				this.updateConfig();			},		},		mounted() {			this.updateConfig();			this.updateData();			this.tagIndex = this.activeIndex;			this.$nextTick(() => {				this.calcScrollPosition();			})		},		methods: {			updateData() {				let data = [];				if (typeof(this.tabData[0])=='string') {					this.tabData.forEach((item, index) => {						data.push({							name: item,						})					});					this.defaultConfig.key = 'name';				} else {					data = JSON.parse(JSON.stringify(this.tabData));				}								this.tabList = data;			},			updateConfig() {				this.defaultConfig = Object.assign(this.defaultConfig, this.config);			},			calcScrollPosition() {								const query = uni.createSelectorQuery().in(this);								query.select('#_scroll').boundingClientRect((res) => {					this.scorll = res;					this.updateTabWidth();				}).exec();			},			updateTabWidth(index = 0) {				let data = this.tabList;								if (data.length == 0) return false;								const query = uni.createSelectorQuery().in(this);								query.select('#_tab_' + index).boundingClientRect((res) => {					data[index]._slider = {						width: res.width,						left: res.left,						scrollLeft: res.left - (data[index - 1] ? data[index - 1]._slider.width : 0),					};										if (this.tagIndex == index) {						this.tabToIndex(this.tagIndex);					}					index++;					if (data.length > index) {						this.updateTabWidth(index);					}				}).exec();			},				tabToIndex(index) {				let _slider = this.tabList[index]._slider;								let width = uni.upx2px(this.defaultConfig.underLineWidth);								if (!width) {					if (this.defaultConfig.itemWidth) {						width = uni.upx2px(this.defaultConfig.itemWidth);					} else {						width = this.tabList[index][this.defaultConfig.key].length * uni.upx2px(this.defaultConfig.fontSize);					}					width += uni.upx2px(this.defaultConfig.underLinePadding) * 2;				}								let scorll_left = this.scorll.left || 0;								this.slider = {					left: _slider.left - scorll_left + (_slider.width - width) / 2,					width: width,					scrollLeft: _slider.scrollLeft - scorll_left,				}			},						tabClick(index) {				this.tagIndex = index;				this.tabToIndex(index);				this.$emit('tabClick', index);			}		}	}</script><style lang="scss" scoped>	._tab-box {		width: 100%;		display: flex;		font-size: 26rpx;		position: relative;		height: 90rpx;		line-height: 90rpx;		z-index: 10;		.scroll-view-h{			white-space:nowrap;			width: 100%;			height: 100%;			box-sizing: border-box;			._scroll-content {				width: 100%;				height: 100%;				position:relative;								._tab-item-box {					height: 100%;					&._flex {						display: flex;						._item {							flex: 1;						}					}					&._clamp {						._item {							overflow:hidden;							text-overflow:ellipsis;							white-space:nowrap;						}					}															._item { 						height: 100%;						display: inline-block;						text-align: center;						padding: 0 30rpx;						position: relative;						text-align: center;												color: #333;						&._active {							color: #e54d42;						}					}				}				._underline {					height: 4rpx;					background-color: #e54d42;					border-radius: 6rpx;					transition: .5s;					position: absolute;					bottom: 0;				}			}		}	}</style>
 |