605 lines
19 KiB
Vue
605 lines
19 KiB
Vue
|
|
<template>
|
|||
|
|
<view class='index-list'>
|
|||
|
|
<view class='index-list__head'>
|
|||
|
|
<input v-model="citySearch" :placeholder='placeholder' class="index-list__input"
|
|||
|
|
placeholder-class="index-list__input__placeholder" />
|
|||
|
|
</view>
|
|||
|
|
<div>
|
|||
|
|
<div class='index-list__scroller'>
|
|||
|
|
<div ref="bigDataTablePanel" class="index-list__big-data__table-panel">
|
|||
|
|
<div ref="bigDataTableBody" class="index-list__big-data__table-body">
|
|||
|
|
<div ref="bigDataTableDataPanel" id="bigDataTableDataPanel"
|
|||
|
|
class="index-list__big-data__table-data-panel" @touchstart="bigDataTouchStartEvent"
|
|||
|
|
@touchmove.stop.prevent="bigDataScrollEvent" @touchend="bigDataTouchEndEvent"
|
|||
|
|
@mousewheel="bigDataScrollEvent">
|
|||
|
|
<div ref="bigDataTableDataMarginSpace" :style="{'margin-top':newMarginTop+'px'}"></div>
|
|||
|
|
<div v-for='item in bigDataFilteredFlatWithLineInfoCurrent' :key='item.id'>
|
|||
|
|
<div v-if='item.__line_info__.isEmptySpace'
|
|||
|
|
class="index-list__group-cell index-list__group-cell--empty-space"></div>
|
|||
|
|
<div v-else-if='!item.__line_info__.isEmptySpace&&item.__line_info__.isHead'
|
|||
|
|
class="index-list__group-head">{{item.username}}</div>
|
|||
|
|
<div v-else-if='!item.__line_info__.isEmptySpace&&!item.__line_info__.isHead'
|
|||
|
|
class="index-list__group-cell" @click="()=>{ itemClickHandler(item)}" :key="item.id"
|
|||
|
|
style="display: flex;" @longpress="()=>{itemLongPress(item)}">
|
|||
|
|
<view>
|
|||
|
|
<image src="../../static/images/tx.png"
|
|||
|
|
style="width:50rpx;height: 50rpx;margin-top: 10rpx;"></image>
|
|||
|
|
</view>
|
|||
|
|
<span
|
|||
|
|
style="padding-left: 20rpx;font-size:34rpx ;letter-spacing: 1rpx;">{{item.username}}</span>
|
|||
|
|
<span
|
|||
|
|
style="padding-left: 20rpx;font-size:34rpx ;letter-spacing: 1rpx;">({{item.phone}})</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
<div v-for='groupKey in Object.keys(bigDataFiltered)' style='' :key='groupKey'>
|
|||
|
|
<div class="index-list__group-head"
|
|||
|
|
:id='"list-archor-"+ encodeURIComponent(groupKey).replace("%","_")'>
|
|||
|
|
{{groupKey}}
|
|||
|
|
</div>
|
|||
|
|
<div class="index-list__group-cell" v-for='city in dataFiltered[groupKey]'
|
|||
|
|
@click="()=>{itemClickHandler(city)}" :clickable='true' :key="city.id">
|
|||
|
|
{{city.username}}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<view v-if='useIndex&&dataFiltered&&Object.keys(dataFiltered).length>0' class='index-list__index'
|
|||
|
|
@touchmove="indexTouchMoveHandler" @touchstart="indexTouchMoveHandler" @touchend="isZoomActiveIndex=false">
|
|||
|
|
<div class='index-list__index__wrapper'>
|
|||
|
|
<div v-for='groupKey in Object.keys(dataFiltered)' :key='groupKey' class='index-list__index__letter'
|
|||
|
|
:class='{"index-list__index__letter--active":currentActiveIndex===groupKey&&isZoomActiveIndex,
|
|||
|
|
"index-list__index__letter--active2":currentActiveIndex===groupKey}'>
|
|||
|
|
{{groupKey}}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
import {
|
|||
|
|
pinyin
|
|||
|
|
} from "@/api/convertPinyin.js";
|
|||
|
|
export default {
|
|||
|
|
name: "missthee-indexlist",
|
|||
|
|
props: {
|
|||
|
|
data: {
|
|||
|
|
type: Object,
|
|||
|
|
default: function() {
|
|||
|
|
return {}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
placeholder: {
|
|||
|
|
type: String,
|
|||
|
|
default: function() {
|
|||
|
|
return '输入关键字查询'
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
useIndex: {
|
|||
|
|
type: Boolean,
|
|||
|
|
default: function() {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
data() {
|
|||
|
|
return {
|
|||
|
|
dataFiltered: {},
|
|||
|
|
currentActiveIndex: '',
|
|||
|
|
isZoomActiveIndex: false,
|
|||
|
|
citySearch: '',
|
|||
|
|
citySeatchDebounce: null,
|
|||
|
|
bigDataFilteredLineHeightTotal: 0,
|
|||
|
|
bigDataFiltered: {},
|
|||
|
|
bigDataFilteredFlatWithLineInfo: [],
|
|||
|
|
bigDataFilteredFlatWithLineInfoCurrent: [],
|
|||
|
|
bigDataTableDataPanelEl: null,
|
|||
|
|
bigDataParam: {
|
|||
|
|
scrollHeight: 0,
|
|||
|
|
dataHeadHeight: 35, // 索引行高
|
|||
|
|
dataRowHeight: 45, // 数据行高
|
|||
|
|
},
|
|||
|
|
bigDataComputedParam: {
|
|||
|
|
dataRowTopMax: 0, //数据行滑到底,移动的最大距离
|
|||
|
|
dataRowTop: 0, //数据行当前移动的距离
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
bigDataScrollActionParam: {
|
|||
|
|
speed: 0,
|
|||
|
|
speedMax: 50,
|
|||
|
|
resistance: 0.5,
|
|||
|
|
prePositionY: null,
|
|||
|
|
preTimestamp: null,
|
|||
|
|
isMouseDown: false,
|
|||
|
|
timeoutObj: null
|
|||
|
|
},
|
|||
|
|
newMarginTop: 0,
|
|||
|
|
islongPress: false, //长按记录变量
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
watch: {
|
|||
|
|
data: {
|
|||
|
|
immediate: true,
|
|||
|
|
handler() {
|
|||
|
|
this.buildDataFiltered()
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
citySearch() {
|
|||
|
|
if (this.citySeatchDebounce) {
|
|||
|
|
clearTimeout(this.citySeatchDebounce)
|
|||
|
|
this.citySeatchDebounce = null
|
|||
|
|
}
|
|||
|
|
this.citySeatchDebounce = setTimeout(() => {
|
|||
|
|
this.buildDataFiltered()
|
|||
|
|
}, 200)
|
|||
|
|
},
|
|||
|
|
dataFiltered: {
|
|||
|
|
deep: true,
|
|||
|
|
handler() {
|
|||
|
|
this.bigDataComputedParam.dataRowTop = 0
|
|||
|
|
this.bigDataBuildData()
|
|||
|
|
this.bigDataUpdateRows()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
mounted() {
|
|||
|
|
this.bigDataTableDataPanelEl = this.$refs.bigDataTableDataPanel
|
|||
|
|
// #ifdef H5
|
|||
|
|
this.bigDataParam.scrollHeight = this.bigDataTableDataPanelEl.offsetHeight
|
|||
|
|
// #endif
|
|||
|
|
// #ifdef APP-VUE || APP
|
|||
|
|
let view = uni.createSelectorQuery().in(this).select("#bigDataTableDataPanel")
|
|||
|
|
view.fields({
|
|||
|
|
size: true
|
|||
|
|
}, res => {
|
|||
|
|
this.bigDataParam.scrollHeight = res.height - 100
|
|||
|
|
this.afterHeight = true;
|
|||
|
|
}).exec()
|
|||
|
|
// #endif
|
|||
|
|
this.bigDataAddEvent()
|
|||
|
|
this.bigDataBuildData()
|
|||
|
|
this.bigDataUpdateRows()
|
|||
|
|
this.bigDataScrollAminate()
|
|||
|
|
},
|
|||
|
|
beforeDestroy() {
|
|||
|
|
this.bigDataClearScrollAnimate()
|
|||
|
|
this.bigDataRemoveEvent()
|
|||
|
|
},
|
|||
|
|
methods: {
|
|||
|
|
indexTouchMoveHandler(e) {
|
|||
|
|
this.isZoomActiveIndex = true
|
|||
|
|
const touch = e.touches[0];
|
|||
|
|
const target = e.currentTarget || e.target
|
|||
|
|
let currentIndex = Math.floor((touch.clientY + Object.keys(this.dataFiltered).length * 15 / 2 -
|
|||
|
|
target.offsetTop) / 15)
|
|||
|
|
currentIndex = Math.min(Object.keys(this.dataFiltered).length - 1, currentIndex)
|
|||
|
|
currentIndex = Math.max(0, currentIndex)
|
|||
|
|
if (Object.keys(this.dataFiltered)[currentIndex] !== this.currentActiveIndex) {
|
|||
|
|
this.currentActiveIndex = Object.keys(this.dataFiltered)[currentIndex]
|
|||
|
|
let currentStartLine = this.bigDataFilteredFlatWithLineInfo.find(item => item.id === 'Head:' + this
|
|||
|
|
.currentActiveIndex)
|
|||
|
|
this.bigDataComputedParam.dataRowTop = currentStartLine.__line_info__.totalHeight -
|
|||
|
|
currentStartLine
|
|||
|
|
.__line_info__.currentHeight
|
|||
|
|
this.bigDataUpdateRows()
|
|||
|
|
}
|
|||
|
|
if ("undefined" !== typeof event) {
|
|||
|
|
event.preventDefault()
|
|||
|
|
event.stopPropagation()
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
itemClickHandler(item) {
|
|||
|
|
if (this.islongPress) {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
let result = {
|
|||
|
|
...item
|
|||
|
|
}
|
|||
|
|
for (let key of Object.keys(result)) {
|
|||
|
|
if (key === '__line_info__') {
|
|||
|
|
delete result[key]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.$emit('select-item', result)
|
|||
|
|
},
|
|||
|
|
itemLongPress(item) {
|
|||
|
|
this.islongPress = true
|
|||
|
|
let result = {
|
|||
|
|
...item
|
|||
|
|
}
|
|||
|
|
for (let key of Object.keys(result)) {
|
|||
|
|
if (key === '__line_info__') {
|
|||
|
|
delete result[key]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let _this = this
|
|||
|
|
uni.setClipboardData({
|
|||
|
|
data: result.phone,
|
|||
|
|
success: function() {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '复制成功',
|
|||
|
|
icon: 'success'
|
|||
|
|
});
|
|||
|
|
setTimeout(() => {
|
|||
|
|
_this.islongPress = false
|
|||
|
|
}, 2000)
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
buildDataFiltered() {
|
|||
|
|
if (!this.data) {
|
|||
|
|
return {}
|
|||
|
|
}
|
|||
|
|
const resultObj = {}
|
|||
|
|
for (const groupkey of Object.keys(this.data)) {
|
|||
|
|
const cityListResult = this.data[groupkey].filter(item =>
|
|||
|
|
item.username.toLowerCase().indexOf(this
|
|||
|
|
.citySearch.toLowerCase()) >= 0
|
|||
|
|
)
|
|||
|
|
if (cityListResult && cityListResult.length > 0) {
|
|||
|
|
resultObj[groupkey] = cityListResult
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
this.dataFiltered = resultObj
|
|||
|
|
},
|
|||
|
|
bigDataAddEvent() {
|
|||
|
|
// #ifdef APP-VUE || APP
|
|||
|
|
// plus.globalEvent.addEventListener('mousewheel', this.bigDataScrollEvent);
|
|||
|
|
// plus.globalEvent.addEventListener('touchmove', this.bigDataScrollEvent);
|
|||
|
|
// plus.globalEvent.addEventListener('touchstart', this.bigDataTouchStartEvent);
|
|||
|
|
// plus.globalEvent.addEventListener('touchend', this.bigDataTouchEndEvent);
|
|||
|
|
// #endif
|
|||
|
|
// #ifdef H5
|
|||
|
|
this.bigDataTableDataPanelEl.addEventListener('mousewheel', this.bigDataScrollEvent);
|
|||
|
|
this.bigDataTableDataPanelEl.addEventListener('touchmove', this.bigDataScrollEvent);
|
|||
|
|
this.bigDataTableDataPanelEl.addEventListener('touchstart', this.bigDataTouchStartEvent);
|
|||
|
|
this.bigDataTableDataPanelEl.addEventListener('touchend', this.bigDataTouchEndEvent);
|
|||
|
|
// #endif
|
|||
|
|
|
|||
|
|
},
|
|||
|
|
bigDataRemoveEvent() {
|
|||
|
|
this.bigDataTableDataPanelEl.removeEventListener('mousewheel', this.bigDataScrollEvent);
|
|||
|
|
this.bigDataTableDataPanelEl.removeEventListener('touchmove', this.bigDataScrollEvent);
|
|||
|
|
this.bigDataTableDataPanelEl.removeEventListener('touchstart', this.bigDataTouchStartEvent);
|
|||
|
|
this.bigDataTableDataPanelEl.removeEventListener('touchend', this.bigDataTouchEndEvent);
|
|||
|
|
},
|
|||
|
|
bigDataTouchStartEvent(e) {
|
|||
|
|
this.bigDataScrollActionParam.isMouseDown = true
|
|||
|
|
this.bigDataScrollActionParam.speed = 0
|
|||
|
|
},
|
|||
|
|
bigDataTouchEndEvent(e) {
|
|||
|
|
this.bigDataScrollActionParam.isMouseDown = false
|
|||
|
|
this.bigDataScrollActionParam.prePositionY = null
|
|||
|
|
},
|
|||
|
|
bigDataScrollEvent(e) {
|
|||
|
|
let scrollEvent = e;
|
|||
|
|
// if (scrollEvent instanceof WheelEvent) {
|
|||
|
|
// #ifdef H5
|
|||
|
|
this.bigDataComputedParam.dataRowTop += (scrollEvent.wheelDelta < 0 ? 1 : -1) * 30;
|
|||
|
|
if (this.bigDataComputedParam.dataRowTop <= 0) {
|
|||
|
|
this.bigDataComputedParam.dataRowTop = 0; //滑块最多滑到顶部
|
|||
|
|
} else if (this.bigDataComputedParam.dataRowTop >= this.bigDataComputedParam.dataRowTopMax) {
|
|||
|
|
this.bigDataComputedParam.dataRowTop = this.bigDataComputedParam.dataRowTopMax; //滑块最多滑到最底部
|
|||
|
|
} else {
|
|||
|
|
e.preventDefault(); //禁用滑轮滚动默认事件。当表格滑动到边缘时再启用默认滚动事件
|
|||
|
|
}
|
|||
|
|
// #endif
|
|||
|
|
// } else
|
|||
|
|
// if (scrollEvent instanceof TouchEvent) {
|
|||
|
|
// #ifdef APP||APP-VUE
|
|||
|
|
if (this.bigDataScrollActionParam.isMouseDown) {
|
|||
|
|
let positionY = scrollEvent.changedTouches[0].clientY
|
|||
|
|
let timeStamp = scrollEvent.timeStamp
|
|||
|
|
let step = 0
|
|||
|
|
this.bigDataScrollActionParam.prePositionY = this.bigDataScrollActionParam.prePositionY ||
|
|||
|
|
positionY
|
|||
|
|
this.bigDataScrollActionParam.preTimeStamp = this.bigDataScrollActionParam.preTimeStamp ||
|
|||
|
|
timeStamp
|
|||
|
|
let timeDuration = timeStamp - this.bigDataScrollActionParam.preTimeStamp;
|
|||
|
|
let velocity;
|
|||
|
|
if (timeDuration === 0) {
|
|||
|
|
velocity = 0
|
|||
|
|
} else {
|
|||
|
|
velocity = (positionY - this.bigDataScrollActionParam.prePositionY) / timeDuration
|
|||
|
|
}
|
|||
|
|
if (this.bigDataScrollActionParam.prePositionY !== null) {
|
|||
|
|
step = positionY - this.bigDataScrollActionParam.prePositionY
|
|||
|
|
this.bigDataComputedParam.dataRowTop -= step
|
|||
|
|
}
|
|||
|
|
this.bigDataScrollActionParam.prePositionY = positionY
|
|||
|
|
this.bigDataScrollActionParam.preTimeStamp = timeStamp
|
|||
|
|
this.bigDataScrollActionParam.speed = velocity * 16
|
|||
|
|
e.preventDefault()
|
|||
|
|
e.stopPropagation()
|
|||
|
|
}
|
|||
|
|
// #endif
|
|||
|
|
// }
|
|||
|
|
this.bigDataUpdateRows();
|
|||
|
|
},
|
|||
|
|
bigDataBuildData() {
|
|||
|
|
this.bigDataFilteredFlatWithLineInfo = []
|
|||
|
|
this.bigDataFilteredLineHeightTotal = 0
|
|||
|
|
for (let key of Object.keys(this.dataFiltered)) {
|
|||
|
|
if (this.dataFiltered[key] && this.dataFiltered[key].length > 0) {
|
|||
|
|
this.bigDataFilteredLineHeightTotal += this.bigDataParam.dataHeadHeight
|
|||
|
|
this.bigDataFilteredFlatWithLineInfo.push({
|
|||
|
|
id: "Head:" + key,
|
|||
|
|
username: key,
|
|||
|
|
__line_info__: {
|
|||
|
|
isEmptySpace: false,
|
|||
|
|
isHead: true,
|
|||
|
|
currentHeight: this.bigDataParam.dataHeadHeight,
|
|||
|
|
totalHeight: this.bigDataFilteredLineHeightTotal
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
this.dataFiltered[key].forEach((item) => {
|
|||
|
|
this.bigDataFilteredLineHeightTotal += this.bigDataParam.dataRowHeight
|
|||
|
|
this.bigDataFilteredFlatWithLineInfo.push({
|
|||
|
|
id: "Row:" + item.id,
|
|||
|
|
username: item.username,
|
|||
|
|
phone: item.phone,
|
|||
|
|
__line_info__: {
|
|||
|
|
isEmptySpace: false,
|
|||
|
|
isHead: false,
|
|||
|
|
currentHeight: this.bigDataParam.dataRowHeight,
|
|||
|
|
totalHeight: this.bigDataFilteredLineHeightTotal
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
this.bigDataFilteredLineHeightTotal += this.bigDataParam.dataRowHeight
|
|||
|
|
this.bigDataFilteredFlatWithLineInfo.push({
|
|||
|
|
id: "EmptyFooter",
|
|||
|
|
username: '',
|
|||
|
|
__line_info__: {
|
|||
|
|
isEmptySpace: true,
|
|||
|
|
isHead: false,
|
|||
|
|
currentHeight: this.bigDataParam.dataRowHeight,
|
|||
|
|
totalHeight: this.bigDataFilteredLineHeightTotal
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
//计算出数据区域滑动到最后一条数据,所需要的位移距离
|
|||
|
|
this.bigDataComputedParam.dataRowTopMax = Math.max(this.bigDataFilteredLineHeightTotal - this.bigDataParam
|
|||
|
|
.scrollHeight, 0)
|
|||
|
|
},
|
|||
|
|
bigDataUpdateRows() {
|
|||
|
|
this.bigDataComputedParam.dataRowTop = Math.max(0, this.bigDataComputedParam.dataRowTop)
|
|||
|
|
this.bigDataComputedParam.dataRowTop = Math.min(this.bigDataComputedParam.dataRowTop, this
|
|||
|
|
.bigDataComputedParam.dataRowTopMax)
|
|||
|
|
if (this.bigDataFilteredFlatWithLineInfo.length > 0) {
|
|||
|
|
//更新数据区的数据,根据滚动的距离,确定可见的第一条数据下标(此方法保证可见数据行内容的更新。注释掉此方法,拖动滚动条,数据会在开始部分一直循环)
|
|||
|
|
//遍历数据,插入窗口中可见的数据行
|
|||
|
|
let startIndex = null
|
|||
|
|
let endIndex = null
|
|||
|
|
|
|||
|
|
for (let i = parseInt(this.bigDataComputedParam.dataRowTop / Math.max(this.bigDataParam.dataRowHeight,
|
|||
|
|
this.bigDataParam.dataHeadHeight), 10) - 1; i < this.bigDataFilteredFlatWithLineInfo
|
|||
|
|
.length; i++) {
|
|||
|
|
if (i < 0) {
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
const totalHeight = this.bigDataFilteredFlatWithLineInfo[i].__line_info__.totalHeight
|
|||
|
|
if (totalHeight >= this.bigDataComputedParam.dataRowTop && startIndex === null) {
|
|||
|
|
startIndex = i
|
|||
|
|
}
|
|||
|
|
if (totalHeight >= (this.bigDataComputedParam.dataRowTop + this.bigDataParam.scrollHeight) &&
|
|||
|
|
endIndex === null) {
|
|||
|
|
endIndex = Math.min(i + 3, this.bigDataFilteredFlatWithLineInfo.length)
|
|||
|
|
} else if (endIndex === null && this.bigDataFilteredFlatWithLineInfo.length < 10) {
|
|||
|
|
endIndex = this.bigDataFilteredFlatWithLineInfo.length
|
|||
|
|
}
|
|||
|
|
if (startIndex !== null && endIndex !== null) {
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
startIndex = startIndex || 0
|
|||
|
|
endIndex = endIndex || 0
|
|||
|
|
this.bigDataFilteredFlatWithLineInfoCurrent = this.bigDataFilteredFlatWithLineInfo.slice(startIndex,
|
|||
|
|
endIndex)
|
|||
|
|
if (this.bigDataFilteredFlatWithLineInfoCurrent && this.bigDataFilteredFlatWithLineInfoCurrent[0]) {
|
|||
|
|
const tmp = this.bigDataFilteredFlatWithLineInfoCurrent[0]
|
|||
|
|
let firstRowHeight = tmp.__line_info__.currentHeight || 0
|
|||
|
|
let firstRowTotalHeight = tmp.__line_info__.totalHeight || 0
|
|||
|
|
//数据区实现拖动滑条的位移效果(保证数据行的滚动效果,注释此方法,拖动滚动条,数据无滚动效果,但内容会更新)
|
|||
|
|
this.newMarginTop = firstRowTotalHeight - this.bigDataComputedParam.dataRowTop - firstRowHeight
|
|||
|
|
if (!this.isZoomActiveIndex) {
|
|||
|
|
this.currentActiveIndex = pinyin.getFullChars(tmp.username).charAt(0).toUpperCase();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
bigDataScrollAminate() {
|
|||
|
|
this.bigDataScrollActionParam.timeoutObj = setInterval(() => {
|
|||
|
|
if (Math.abs(this.bigDataScrollActionParam.speed) > 0 && !this.bigDataScrollActionParam
|
|||
|
|
.isMouseDown) {
|
|||
|
|
this.bigDataScrollActionParam.speed = (this.bigDataScrollActionParam.speed >= 0 ? 1 : -1) *
|
|||
|
|
Math.min(this.bigDataScrollActionParam.speedMax, Math.max(0, Math.abs(this
|
|||
|
|
.bigDataScrollActionParam.speed) - this.bigDataScrollActionParam
|
|||
|
|
.resistance))
|
|||
|
|
this.bigDataComputedParam.dataRowTop -= this.bigDataScrollActionParam.speed
|
|||
|
|
this.bigDataUpdateRows()
|
|||
|
|
}
|
|||
|
|
}, 16)
|
|||
|
|
},
|
|||
|
|
bigDataClearScrollAnimate() {
|
|||
|
|
if (this.bigDataScrollActionParam.timeoutObj) {
|
|||
|
|
clearInterval(this.bigDataScrollActionParam.timeoutObj)
|
|||
|
|
this.bigDataScrollActionParam.timeoutObj = null
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang='scss' scoped>
|
|||
|
|
* {
|
|||
|
|
font-family: Consolas, sans-serif;
|
|||
|
|
box-sizing: border-box !important;
|
|||
|
|
margin: 0;
|
|||
|
|
padding: 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
.index-list__index__letter--active2 {
|
|||
|
|
color: red;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.index-list__index__letter {
|
|||
|
|
margin: 5px 0;
|
|||
|
|
font-size: 20px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.index-list {
|
|||
|
|
position: absolute;
|
|||
|
|
top: 0;
|
|||
|
|
bottom: 0;
|
|||
|
|
width: 100%;
|
|||
|
|
|
|||
|
|
&__head {
|
|||
|
|
position: absolute;
|
|||
|
|
top: 0;
|
|||
|
|
width: 100%;
|
|||
|
|
height: 50px;
|
|||
|
|
overflow: hidden;
|
|||
|
|
background-color: $uni-bg-color;
|
|||
|
|
border-bottom: 1px solid $uni-bg-color-grey;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&__input {
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
width: 90%;
|
|||
|
|
height: 30px;
|
|||
|
|
padding: 0 20px;
|
|||
|
|
margin: auto;
|
|||
|
|
height: 30px;
|
|||
|
|
margin: 10px auto;
|
|||
|
|
line-height: 30px;
|
|||
|
|
background-color: $uni-bg-color-grey;
|
|||
|
|
border-radius: 30px;
|
|||
|
|
font-size: 12px;
|
|||
|
|
color: $uni-text-color;
|
|||
|
|
|
|||
|
|
&__placeholder {
|
|||
|
|
text-align: center;
|
|||
|
|
color: $uni-text-color-placeholder;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&__scroller {
|
|||
|
|
position: absolute;
|
|||
|
|
top: 50px;
|
|||
|
|
bottom: 0;
|
|||
|
|
width: 100%;
|
|||
|
|
background-color: white;
|
|||
|
|
overflow-x: hidden;
|
|||
|
|
overflow-y: auto;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&__big-data {
|
|||
|
|
|
|||
|
|
&__table-panel {
|
|||
|
|
height: 100%;
|
|||
|
|
width: 100%;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&__table-body {
|
|||
|
|
/*因为数据区与滚动条要使用position:absolute做成左右固定布局,table-body作为其两节点的父节点,使用position: relative*/
|
|||
|
|
position: relative;
|
|||
|
|
height: 100%;
|
|||
|
|
overflow: hidden;
|
|||
|
|
background-color: white;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&__table-data-panel {
|
|||
|
|
overflow: hidden;
|
|||
|
|
position: absolute;
|
|||
|
|
left: 0;
|
|||
|
|
/*right值宽度等于滚动条的宽度。也可不设置,但滚动条会覆盖表格的最右侧*/
|
|||
|
|
/*right: 15px;*/
|
|||
|
|
width: 100%;
|
|||
|
|
height: 100%;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&__group-head {
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
background-color: $uni-bg-color-grey;
|
|||
|
|
color: $uni-text-color-grey;
|
|||
|
|
height: 35px;
|
|||
|
|
line-height: 45px;
|
|||
|
|
padding: 0 0 0 15px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&__group-cell {
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
background-color: $uni-bg-color;
|
|||
|
|
color: $uni-text-color;
|
|||
|
|
font-size: 14px;
|
|||
|
|
font-family: SourceHanSansSC-Regular, SourceHanSansSC;
|
|||
|
|
height: 45px;
|
|||
|
|
line-height: 45px;
|
|||
|
|
padding: 0 0 0 15px;
|
|||
|
|
|
|||
|
|
&:after {
|
|||
|
|
display: block;
|
|||
|
|
position: absolute;
|
|||
|
|
content: '';
|
|||
|
|
width: 100%;
|
|||
|
|
height: 1px;
|
|||
|
|
background-color: $uni-bg-color-grey;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&:active {
|
|||
|
|
background-color: $uni-bg-color-hover;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&--empty-space {
|
|||
|
|
&:active {
|
|||
|
|
background-color: white;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&__index {
|
|||
|
|
position: absolute;
|
|||
|
|
right: 0;
|
|||
|
|
top: 50%;
|
|||
|
|
transform: translateY(-50%);
|
|||
|
|
|
|||
|
|
&__wrapper {
|
|||
|
|
width: 20px;
|
|||
|
|
margin: 0 7px 0 0;
|
|||
|
|
text-align: center;
|
|||
|
|
background-color: rgba(0, 0, 0, 0.03);
|
|||
|
|
border-radius: 10px;
|
|||
|
|
color: $uni-text-color-grey;
|
|||
|
|
padding: 10px 0;
|
|||
|
|
font-family: Consolas, sans-serif;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&__letter {
|
|||
|
|
display: block;
|
|||
|
|
height: 15px !important;
|
|||
|
|
line-height: 15px !important;
|
|||
|
|
transition: transform 0.1s;
|
|||
|
|
|
|||
|
|
&--active {
|
|||
|
|
transition: none;
|
|||
|
|
font-weight: bold;
|
|||
|
|
font-size: 50px;
|
|||
|
|
transform: translateX(-70px);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|