178 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
		
		
			
		
	
	
			178 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
|  | <template> | ||
|  |   <view class="tn-scroll-list-class tn-scroll-list"> | ||
|  |     <scroll-view | ||
|  |       class="tn-scroll-list__scroll-view" | ||
|  |       scroll-x | ||
|  |       :upper-threshold="0" | ||
|  |       :lower-threshold="0" | ||
|  |       @scroll="scrollHandler" | ||
|  |       @scrolltoupper="scrollToUpperHandler" | ||
|  |       @scrolltolower="scrollToLowerHandler" | ||
|  |     > | ||
|  |       <view class="tn-scroll-list__scroll-view__content"> | ||
|  |         <slot></slot> | ||
|  |       </view> | ||
|  |     </scroll-view> | ||
|  |      | ||
|  |     <!-- 指示器--> | ||
|  |     <view | ||
|  |       v-if="indicator" | ||
|  |       class="tn-scroll-list__indicator" | ||
|  |       :style="[indicatorStyle]" | ||
|  |     > | ||
|  |       <view class="tn-scroll-list__indicator__line" :style="[lineStyle]"> | ||
|  |         <view class="tn-scroll-list__indicator__line__bar" :style="[barStyle]"></view> | ||
|  |       </view> | ||
|  |     </view> | ||
|  |   </view> | ||
|  | </template> | ||
|  | 
 | ||
|  | <script> | ||
|  |   export default { | ||
|  |     name: 'tn-scroll-list', | ||
|  |     props: { | ||
|  |       // 是否显示指示器
 | ||
|  |       indicator: { | ||
|  |         type: Boolean, | ||
|  |         default: true | ||
|  |       }, | ||
|  |       // 指示器整体宽度
 | ||
|  |       indicatorWidth: { | ||
|  |         type: [String, Number], | ||
|  |         default: 50 | ||
|  |       }, | ||
|  |       // 指示器滑块的宽度
 | ||
|  |       indicatorBarWidth: { | ||
|  |         type: [String, Number], | ||
|  |         default: 20 | ||
|  |       }, | ||
|  |       // 指示器颜色
 | ||
|  |       indicatorColor: { | ||
|  |         type: String, | ||
|  |         default: '#E6E6E6' | ||
|  |       }, | ||
|  |       // 指示器激活时颜色
 | ||
|  |       indicatorActiveColor: { | ||
|  |         type: String, | ||
|  |         default: '#01BEFF' | ||
|  |       }, | ||
|  |       // 自定义指示器样式
 | ||
|  |       indicatorStyle: { | ||
|  |         type: Object, | ||
|  |         default() { | ||
|  |           return {} | ||
|  |         } | ||
|  |       } | ||
|  |     }, | ||
|  |     computed: { | ||
|  |       // 指示器滑块样式
 | ||
|  |       barStyle() { | ||
|  |         let style = {} | ||
|  |         // 获取滑动距离的比值
 | ||
|  |         // 滑块当前移动距离与总需滑动距离(指示器的总宽度减去滑块宽度)的比值 = scroll-view的滚动距离与目标滚动距离(scroll-view的实际宽度减去包裹元素的宽度)之比
 | ||
|  |         const scrollLeft = this.scrollInfo.scrollLeft, | ||
|  |           scrollWidth = this.scrollInfo.scrollWidth, | ||
|  |           barAllMoveWidth = uni.upx2px(this.indicatorWidth) - uni.upx2px(this.indicatorBarWidth); | ||
|  |         const x = scrollLeft / (scrollWidth - this.scrollWidth) * barAllMoveWidth | ||
|  |         style.transform = `translateX(${x}px)` | ||
|  |         // 设置滑块的宽度和背景颜色
 | ||
|  |         style.width = `${this.indicatorBarWidth}rpx` | ||
|  |         style.backgroundColor = this.indicatorActiveColor | ||
|  |         return style | ||
|  |       }, | ||
|  |       // 指示器整体样式
 | ||
|  |       lineStyle() { | ||
|  |         let style = {} | ||
|  |         style.width = `${this.indicatorWidth}rpx` | ||
|  |         style.backgroundColor = this.indicatorColor | ||
|  |         return style | ||
|  |       } | ||
|  |     }, | ||
|  |     data() { | ||
|  |       return { | ||
|  |         // 滑动时滑块信息
 | ||
|  |         scrollInfo: { | ||
|  |           scrollLeft: 0, | ||
|  |           scrollWidth: 0 | ||
|  |         }, | ||
|  |         // 滑动区域的宽度
 | ||
|  |         scrollWidth: 0 | ||
|  |       } | ||
|  |     }, | ||
|  |     mounted() { | ||
|  |       this.$nextTick(() => { | ||
|  |         this.init() | ||
|  |       }) | ||
|  |     }, | ||
|  |     methods: { | ||
|  |       // 初始化
 | ||
|  |       init() { | ||
|  |         this.getComponentWidth() | ||
|  |       }, | ||
|  |       // 处理滚动事件
 | ||
|  |       scrollHandler(event) { | ||
|  |         this.scrollInfo = event.detail | ||
|  |       }, | ||
|  |       // 滚动到最左边触发事件
 | ||
|  |       scrollToUpperHandler() { | ||
|  |         this.$emit('left') | ||
|  |         this.scrollInfo.scrollLeft = 0 | ||
|  |       }, | ||
|  |       // 滚动到最右边触发事件
 | ||
|  |       scrollToLowerHandler() { | ||
|  |         this.$emit('right') | ||
|  |         // this.scrollInfo.scrollLeft = uni.upx2px(this.indicatorWidth) - uni.upx2px(this.indicatorBarWidth)
 | ||
|  |       }, | ||
|  |       // 获取组件的宽度
 | ||
|  |       getComponentWidth() { | ||
|  |         this._tGetRect('.tn-scroll-list').then(res => { | ||
|  |           if (!res) { | ||
|  |             setTimeout(() => { | ||
|  |               this.getComponentWidth() | ||
|  |             }, 10) | ||
|  |             return | ||
|  |           } | ||
|  |           this.scrollWidth = res.width | ||
|  |         }) | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | </script> | ||
|  | 
 | ||
|  | <style lang="scss" scoped> | ||
|  |    | ||
|  |   .tn-scroll-list { | ||
|  |     padding-bottom: 20rpx; | ||
|  |      | ||
|  |     &__scroll-view { | ||
|  |       display: flex; | ||
|  |       flex-direction: row; | ||
|  |        | ||
|  |       &__content { | ||
|  |         display: flex; | ||
|  |         flex-direction: row; | ||
|  |       } | ||
|  |     } | ||
|  |      | ||
|  |     &__indicator { | ||
|  |       display: flex; | ||
|  |       flex-direction: row; | ||
|  |       justify-content: center; | ||
|  |       margin-top: 30rpx; | ||
|  |        | ||
|  |       &__line { | ||
|  |         width: 120rpx; | ||
|  |         height: 8rpx; | ||
|  |         border-radius: 200rpx; | ||
|  |         overflow: hidden; | ||
|  |          | ||
|  |         &__bar { | ||
|  |           width: 40rpx; | ||
|  |           height: 8rpx; | ||
|  |           border-radius: 200rpx; | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | </style> |