<template> <view class="tm-quickIndex " :style="{ height: activeHeight_watch + 'px' }"> <view :style="{ height: activeHeight_watch + 'px' }"> <tm-loadding v-if="loadding" label="处理中..."></tm-loadding> <scroll-view scroll-y :class="[black_tmeme?'grey-darken-4':'white']" :style="{ height: activeHeight_watch + 'px', }" @scroll="scrollIn" :scroll-into-view="guid+'_'+(isScroll?'':active_value)"> <view v-for="(item,index) in dataList" :key="index" :id="guid+'_'+index" class="tm-quickIndex-item"> <view :class="[black_tmeme?'grey-darken-5':'grey-lighten-4 text']" class=" text-size-s text-weight-b px-32 py-12">{{item.title}}</view> <view> <view v-for="(item2,index2) in item.children" :key="index2"> <slot name="cell" :data="{prevent:index,children:index2,total:item.children.length,item:item2,title:item2[rangKey],color:color_tmeme,black:black_tmeme}"> <view :class="[index2!==item.children.length-1?'border-grey-lighten-4-b-1 ':'',black_tmeme?'bk':'']" class="mx-32 py-24 flex-start" @click="changeIndex(index,index2,item2)"> <view v-if="item2['icon']" style="width: 48rpx;height: 48rpx;" class="mr-24 rounded flex-center overflow"> <tm-icons :size="48" :name="item2['icon']"></tm-icons> </view> <view class="text-size-n"> {{item2[rangKey]}} </view> </view> </slot> </view> </view> </view> </scroll-view> </view> <view class="tm-quickIndex-index flex-center flex-col pr-16" :style="{ height: activeHeight_watch + 'px' }"> <view v-if="showtips" :class="[`text-${color_tmeme}`,black_tmeme?'bk':'']" class="tm-quickIndex-index-Tips absolute rounded shadow-10 flex-center white text-size-g text-weight-b"> {{ returnIndexStr(scrollIndx) }} </view> <!-- <view v-if="scrollInBarIndex" :class="[`text-${color}`]" class="tm-quickIndex-index-Tips absolute rounded shadow-10 flex-center white text-size-g text-weight-b"> {{returnIndexStr(scrollIndx)}} :class="[scrollIndx==index?`text-${color} text-weight-b`:'']" </view> --> <view v-if="activeHeight_watch>0" @touchend.stop.prevent="indexMove($event,'end')" @touchmove.stop.prevent="indexMove($event,'scroll')" class="tm-quickIndex-index-Bk round-24 shadow-3 " :class="[black_tmeme?'grey-darken-5 bk':'white']"> <view @click.stop="acitveItemClick($event,index)" class="tm-quickIndex-index-item text-size-xxs flex-center px-2" v-for="(item,index) in dataList" :key="index"> {{ returnIndexStr(index) }} </view> </view> </view> </view> </template> <script> /** * 快速索引 * @property {Array} list = [] 默认:[],列表数据,格式:[{title:"汽车品牌",children:[{title:"宝马"},{title:"奔驰"}]}] * @property {String} rang-key = [] 默认:'title',列表对象key, * @property {String | Number} height = [] 默认:0,高度,默认为0时,自动使用屏幕的高度。 * @property {Number} value = [] 默认:0,当前滚动的索引位置,推荐使用v-model或者value.sync * @property {String} color = [] 默认:primary,主题色。 * @property {Function} change 点击列表项时产生的事件,返回参数:{prent:父Index,children:子index,data:项数据。} * @example <tm-quickIndex :list='[{title:"汽车品牌",children:[{title:"宝马"},{title:"奔驰"}]}]'></tm-quickIndex> * 如果 不提供index索引字符将截取title第一个字符作为索引。如果title第一个没有将使用自建的数字索引。 */ import tmIcons from "@/tm-vuetify/components/tm-icons/tm-icons.vue" import tmLoadding from "@/tm-vuetify/components/tm-loadding/tm-loadding.vue" export default { components:{tmIcons,tmLoadding}, name: 'tm-quickIndex', model: { prop: 'value', event: 'input' }, props: { // 高度,默认为0时,自动使用屏幕的高度。 height: { type: String | Number, default: 0 }, // 当前滚动的位置。 value: { type: Number, default: 0 }, // 当前滚动的位置。 color: { type: String, default: "primary" }, list: { type: Array, default: () => { return []; } }, rangKey: { type: String, default: "title" }, black: { type: String|Boolean, default: null }, // 跟随主题色的改变而改变。 fllowTheme:{ type:Boolean|String, default:true } }, watch: { value: function() { this.active = this.value; this.isScroll=false; this.scrollIndx = this.value; }, list:{ deep:true, handler(){ this.dataList = this.list; } } }, computed: { black_tmeme: function() { if (this.black !== null) return this.black; return this.$tm.vx.state().tmVuetify.black; }, color_tmeme:function(){ if(this.$tm.vx.state().tmVuetify.color!==null&&this.$tm.vx.state().tmVuetify.color && this.fllowTheme){ return this.$tm.vx.state().tmVuetify.color; } return this.color; }, active: { get: function() { return this.active_value; }, set: async function(val) { this.active_value = val; this.$emit('input', val); this.$emit('update:value', val); let t = this; this.showtips = true; let idx = 5655555 clearTimeout(idx) idx = setTimeout(function(){ t.showtips = false; },500) } }, activeHeight_watch: { get: function() { return this.activeHeight; }, set: function(val) { this.activeHeight = val; } } }, data() { return { minTop:0, activeHeight: 0, guid: "", active_value: 0, listBound: [], nowIndex: 0, showtips: false, isScroll: true, quinkBar: null, scrollIndx: 0, scrollInBarIndex: false, dataList:[], loadding:true }; }, async mounted() { this.guid = uni.$tm.guid(); let t = this; this.activeHeight_watch = uni.upx2px(this.height); this.loadding=true; await uni.$tm.sleep(50) this.dataList = [...this.list]; this.$nextTick(async function() { if (!this.activeHeight_watch) { let sysinfo = uni.getSystemInfoSync(); this.activeHeight_watch = sysinfo.windowHeight; } let df = await this.$Querey(".tm-quickIndex",this).catch(e=>{}); this.minTop = df[0].top; let indexbar = await t.$Querey(".tm-quickIndex-index-Bk", t).catch(e => {}) t.quinkBar = indexbar[0] await uni.$tm.sleep(100) t.active = t.value; uni.createSelectorQuery().in(t).selectAll('.tm-quickIndex-item') .boundingClientRect(res => { res.forEach(item => { t.listBound.push(item.top) }) t.loadding=false; }).exec() }); }, methods: { returnIndexStr(index){ let item = this.list[index]; if(!item || typeof item === 'undefined') return; if(item['index']&& typeof item['index'] !=='undefined'){ return item['index']; }else{ if(item[this.rangKey][0]&& typeof item[this.rangKey][0] !=='undefined'){ return item[this.rangKey][0]; } } return index+1 }, scrollIn(e) { let t = this; let y = e.detail.scrollTop; this.isScroll = true; function chatIndex(min) { let index = 0; for (let i = 0; i < t.listBound.length; i++) { if (t.listBound[i] >= min + t.minTop+1) { index = i; break; } } return index; } this.nowIndex = chatIndex(y) - 1; }, changeIndex(prentindex, childrenindex, item) { this.$emit('change', { prent: prentindex, children: childrenindex, data: item }) }, async acitveItemClick(e, indx) { this.isScroll = false; if (this.list.length <= 0) return; this.active = indx; }, async indexMove(e, type) { let t = this; if (this.list.length <= 0) return; if (e.changedTouches.length > 1) return; let y = e.changedTouches[0].clientY; let itemHeight = uni.upx2px(40); let ClickTop = e.target.offsetTop; let index = 0; if (y <= this.quinkBar.top) { index = 0; } else if (y >= this.quinkBar.bottom) { index = this.list.length - 1; } else { let xy = y - this.quinkBar.top index = Math.floor(xy / itemHeight); } if(index>=this.list.length-1) index = this.list.length-1 if(index<=0) index = 0; this.isScroll = false; if(this.scrollIndx!==index){ this.scrollIndx = index } if(this.active!==index){ this.active = index; } if (type == 'end') { t.scrollInBarIndex = false; } else { t.scrollInBarIndex = true; } } }, }; </script> <style lang="scss" scoped> .tm-quickIndex { position: relative; .tm-quickIndex-index { position: absolute; right: 0upx; top: 0; .tm-quickIndex-index-item { width: 40rpx; height: 40rpx; // background: rgba(255,255,255,0.1); } .tm-quickIndex-index-Tips { right: 160rpx; width: 100rpx; height: 100rpx; } } } </style>