You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
356 lines
8.3 KiB
356 lines
8.3 KiB
<template> |
|
<view class="uni-indexed-list" ref="list" id="list"> |
|
<!-- #ifdef APP-NVUE --> |
|
<list class="uni-indexed-list__scroll" scrollable="true" show-scrollbar="false"> |
|
<cell v-for="(list, idx) in lists" :key="idx" :ref="'uni-indexed-list-' + idx"> |
|
<!-- #endif --> |
|
<!-- #ifndef APP-NVUE --> |
|
<scroll-view :scroll-into-view="scrollViewId" class="uni-indexed-list__scroll" scroll-y> |
|
<view v-for="(list, idx) in lists" :key="idx" :id="'uni-indexed-list-' + idx"> |
|
<!-- #endif --> |
|
<indexed-list-item :list="list" :loaded="loaded" :idx="idx" :showSelect="showSelect" @itemClick="onClick"></indexed-list-item> |
|
<!-- #ifndef APP-NVUE --> |
|
</view> |
|
</scroll-view> |
|
<!-- #endif --> |
|
<!-- #ifdef APP-NVUE --> |
|
</cell> |
|
</list> |
|
<!-- #endif --> |
|
<view class="uni-indexed-list__menu" :class="touchmove ? 'uni-indexed-list__menu--active' : ''" @touchstart="touchStart" @touchmove.stop.prevent="touchMove" @touchend="touchEnd" @mousedown.stop="mousedown" @mousemove.stop.prevent="mousemove" @mouseleave.stop="mouseleave"> |
|
<view v-for="(list, key) in lists" :key="key" class="uni-indexed-list__menu-item"> |
|
<text class="uni-indexed-list__menu-text" :class="touchmoveIndex == key ? 'uni-indexed-list__menu-text--active' : ''">{{ list.key }}</text> |
|
</view> |
|
</view> |
|
<view v-if="touchmove" class="uni-indexed-list__alert-wrapper"> |
|
<text class="uni-indexed-list__alert">{{ lists[touchmoveIndex].key }}</text> |
|
</view> |
|
</view> |
|
</template> |
|
<script> |
|
import indexedListItem from './uni-indexed-list-item.vue' |
|
// #ifdef APP-NVUE |
|
const dom = weex.requireModule('dom'); |
|
// #endif |
|
// #ifdef APP-PLUS |
|
function throttle(func, delay) { |
|
var prev = Date.now(); |
|
return function() { |
|
var context = this; |
|
var args = arguments; |
|
var now = Date.now(); |
|
if (now - prev >= delay) { |
|
func.apply(context, args); |
|
prev = Date.now(); |
|
} |
|
} |
|
} |
|
|
|
function touchMove(e) { |
|
let pageY = e.touches[0].pageY |
|
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight) |
|
if (this.touchmoveIndex === index) { |
|
return false |
|
} |
|
let item = this.lists[index] |
|
if (item) { |
|
// #ifndef APP-NVUE |
|
this.scrollViewId = 'uni-indexed-list-' + index |
|
this.touchmoveIndex = index |
|
// #endif |
|
// #ifdef APP-NVUE |
|
dom.scrollToElement(this.$refs['uni-indexed-list-' + index][0], { |
|
animated: false |
|
}) |
|
this.touchmoveIndex = index |
|
// #endif |
|
} |
|
} |
|
const throttleTouchMove = throttle(touchMove, 40) |
|
// #endif |
|
|
|
/** |
|
* IndexedList 索引列表 |
|
* @description 用于展示索引列表 |
|
* @tutorial https://ext.dcloud.net.cn/plugin?id=375 |
|
* @property {Boolean} showSelect = [true|false] 展示模式 |
|
* @value true 展示模式 |
|
* @value false 选择模式 |
|
* @property {Object} options 索引列表需要的数据对象 |
|
* @event {Function} click 点击列表事件 ,返回当前选择项的事件对象 |
|
* @example <uni-indexed-list options="" showSelect="false" @click=""></uni-indexed-list> |
|
*/ |
|
export default { |
|
name: 'UniIndexedList', |
|
components: { |
|
indexedListItem |
|
}, |
|
props: { |
|
options: { |
|
type: Array, |
|
default () { |
|
return [] |
|
} |
|
}, |
|
showSelect: { |
|
type: Boolean, |
|
default: false |
|
} |
|
}, |
|
data() { |
|
return { |
|
lists: [], |
|
winHeight: 0, |
|
itemHeight: 0, |
|
winOffsetY: 0, |
|
touchmove: false, |
|
touchmoveIndex: -1, |
|
scrollViewId: '', |
|
touchmovable: true, |
|
loaded: false, |
|
isPC: false |
|
} |
|
}, |
|
watch: { |
|
options: { |
|
handler: function() { |
|
this.setList() |
|
}, |
|
deep: true |
|
} |
|
}, |
|
mounted() { |
|
// #ifdef H5 |
|
this.isPC = this.IsPC() |
|
// #endif |
|
setTimeout(() => { |
|
this.setList() |
|
}, 50) |
|
setTimeout(() => { |
|
this.loaded = true |
|
}, 300); |
|
}, |
|
methods: { |
|
setList() { |
|
let index = 0; |
|
this.lists = [] |
|
this.options.forEach((value, index) => { |
|
if (value.data.length === 0) { |
|
return |
|
} |
|
let indexBefore = index |
|
let items = value.data.map(item => { |
|
let obj = {} |
|
obj['key'] = value.letter |
|
obj['name'] = item |
|
obj['itemIndex'] = index |
|
index++ |
|
obj.checked = item.checked ? item.checked : false |
|
return obj |
|
}) |
|
this.lists.push({ |
|
title: value.letter, |
|
key: value.letter, |
|
items: items, |
|
itemIndex: indexBefore |
|
}) |
|
}) |
|
// #ifndef APP-NVUE |
|
uni.createSelectorQuery() |
|
.in(this) |
|
.select('#list') |
|
.boundingClientRect() |
|
.exec(ret => { |
|
this.winOffsetY = ret[0].top |
|
this.winHeight = ret[0].height |
|
this.itemHeight = this.winHeight / this.lists.length |
|
}) |
|
// #endif |
|
// #ifdef APP-NVUE |
|
dom.getComponentRect(this.$refs['list'], (res) => { |
|
this.winOffsetY = res.size.top |
|
this.winHeight = res.size.height |
|
this.itemHeight = this.winHeight / this.lists.length |
|
}) |
|
// #endif |
|
}, |
|
touchStart(e) { |
|
this.touchmove = true |
|
let pageY = this.isPC ? e.pageY : e.touches[0].pageY |
|
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight) |
|
let item = this.lists[index] |
|
if (item) { |
|
this.scrollViewId = 'uni-indexed-list-' + index |
|
this.touchmoveIndex = index |
|
// #ifdef APP-NVUE |
|
dom.scrollToElement(this.$refs['uni-indexed-list-' + index][0], { |
|
animated: false |
|
}) |
|
// #endif |
|
} |
|
}, |
|
touchMove(e) { |
|
// #ifndef APP-PLUS |
|
let pageY = this.isPC ? e.pageY : e.touches[0].pageY |
|
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight) |
|
if (this.touchmoveIndex === index) { |
|
return false |
|
} |
|
let item = this.lists[index] |
|
if (item) { |
|
this.scrollViewId = 'uni-indexed-list-' + index |
|
this.touchmoveIndex = index |
|
} |
|
// #endif |
|
// #ifdef APP-PLUS |
|
throttleTouchMove.call(this, e) |
|
// #endif |
|
}, |
|
touchEnd() { |
|
this.touchmove = false |
|
this.touchmoveIndex = -1 |
|
}, |
|
|
|
/** |
|
* 兼容 PC @tian |
|
*/ |
|
|
|
mousedown(e) { |
|
if (!this.isPC) return |
|
this.touchStart(e) |
|
}, |
|
mousemove(e) { |
|
if (!this.isPC) return |
|
this.touchMove(e) |
|
}, |
|
mouseleave(e) { |
|
if (!this.isPC) return |
|
this.touchEnd(e) |
|
}, |
|
|
|
// #ifdef H5 |
|
IsPC() { |
|
var userAgentInfo = navigator.userAgent; |
|
var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]; |
|
var flag = true; |
|
for (let v = 0; v < Agents.length - 1; v++) { |
|
if (userAgentInfo.indexOf(Agents[v]) > 0) { |
|
flag = false; |
|
break; |
|
} |
|
} |
|
return flag; |
|
}, |
|
// #endif |
|
|
|
|
|
onClick(e) { |
|
let { |
|
idx, |
|
index |
|
} = e |
|
let obj = {} |
|
for (let key in this.lists[idx].items[index]) { |
|
obj[key] = this.lists[idx].items[index][key] |
|
} |
|
let select = [] |
|
if (this.showSelect) { |
|
this.lists[idx].items[index].checked = !this.lists[idx].items[index].checked |
|
this.lists.forEach((value, idx) => { |
|
value.items.forEach((item, index) => { |
|
if (item.checked) { |
|
let obj = {} |
|
for (let key in this.lists[idx].items[index]) { |
|
obj[key] = this.lists[idx].items[index][key] |
|
} |
|
select.push(obj) |
|
} |
|
}) |
|
}) |
|
} |
|
this.$emit('click', { |
|
item: obj, |
|
select: select |
|
}) |
|
} |
|
} |
|
} |
|
</script> |
|
<style scoped> |
|
.uni-indexed-list { |
|
position: absolute; |
|
left: 0; |
|
top: 0; |
|
right: 0; |
|
bottom: 0; |
|
/* #ifndef APP-NVUE */ |
|
display: flex; |
|
/* #endif */ |
|
flex-direction: row; |
|
} |
|
|
|
.uni-indexed-list__scroll { |
|
flex: 1; |
|
} |
|
|
|
.uni-indexed-list__menu { |
|
width: 24px; |
|
background-color: lightgrey; |
|
/* #ifndef APP-NVUE */ |
|
display: flex; |
|
/* #endif */ |
|
flex-direction: column; |
|
} |
|
|
|
.uni-indexed-list__menu-item { |
|
/* #ifndef APP-NVUE */ |
|
display: flex; |
|
/* #endif */ |
|
flex: 1; |
|
align-items: center; |
|
justify-content: center; |
|
/* #ifdef H5 */ |
|
cursor: pointer; |
|
/* #endif */ |
|
} |
|
|
|
.uni-indexed-list__menu-text { |
|
line-height: 20px; |
|
font-size: 12px; |
|
text-align: center; |
|
color: #aaa; |
|
} |
|
|
|
.uni-indexed-list__menu--active { |
|
background-color: #c8c8c8; |
|
} |
|
|
|
.uni-indexed-list__menu-text--active { |
|
color: #007aff; |
|
} |
|
|
|
.uni-indexed-list__alert-wrapper { |
|
position: absolute; |
|
left: 0; |
|
top: 0; |
|
right: 0; |
|
bottom: 0; |
|
/* #ifndef APP-NVUE */ |
|
display: flex; |
|
/* #endif */ |
|
flex-direction: row; |
|
align-items: center; |
|
justify-content: center; |
|
} |
|
|
|
.uni-indexed-list__alert { |
|
width: 80px; |
|
height: 80px; |
|
border-radius: 80px; |
|
text-align: center; |
|
line-height: 80px; |
|
font-size: 35px; |
|
color: #fff; |
|
background-color: rgba(0, 0, 0, 0.5); |
|
} |
|
</style> |