You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

329 lines
8.9 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<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>