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.
364 lines
8.8 KiB
364 lines
8.8 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 --> |
|
<uni-indexed-list-item :list="list" :loaded="loaded" :idx="idx" :showSelect="showSelect" @itemClick="onClick"></uni-indexed-list-item> |
|
<!-- #ifndef APP-NVUE --> |
|
</view> |
|
</scroll-view> |
|
<!-- #endif --> |
|
<!-- #ifdef APP-NVUE --> |
|
</cell> |
|
</list> |
|
<!-- #endif --> |
|
<view :class="touchmove ? 'uni-indexed-list__menu--active' : ''" @touchstart="touchStart" @touchmove.stop.prevent="touchMove" @touchend="touchEnd" class="uni-indexed-list__menu"> |
|
<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.value }}</text> |
|
</view> |
|
</view> |
|
<view v-if="touchmove" class="uni-indexed-list__alert-wrapper"> |
|
<text class="uni-indexed-list__alert">{{ lists[touchmoveIndex] }}</text> |
|
</view> |
|
</view> |
|
</template> |
|
<script> |
|
import uniIcons from '../uni-icons/uni-icons.vue' |
|
import uniIndexedListItem from './uni-data-indexed-list-item.vue' |
|
import clientdb from './clientdb.js' |
|
// #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 索引列表需要的数据对象 |
|
* @property {String|DBCollectionString} collection 表名 |
|
* @property {String|ClientDBActionString} action 云端执行数据库查询的前或后,触发某个action函数操作,进行预处理或后处理 |
|
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割 |
|
* @property {String} orderby 排序字段及正序倒叙设置 |
|
* @property {String|JQLString} where 查询条件 |
|
* @event {Function} click 点击列表事件 ,返回当前选择项的事件对象 |
|
* @example <uni-indexed-list options="" showSelect="false" @click=""></uni-indexed-list> |
|
*/ |
|
export default { |
|
name: 'UniDataIndexedList', |
|
mixins: [clientdb], |
|
components: { |
|
uniIcons, |
|
uniIndexedListItem |
|
}, |
|
props: { |
|
options: { |
|
type: Array, |
|
default () { |
|
return [] |
|
} |
|
}, |
|
localdata: { |
|
type: Array, |
|
default () { |
|
return [] |
|
} |
|
}, |
|
showSelect: { |
|
type: Boolean, |
|
default: false |
|
} |
|
}, |
|
data() { |
|
return { |
|
lists: [], |
|
winHeight: 0, |
|
itemHeight: 0, |
|
winOffsetY: 0, |
|
touchmove: false, |
|
touchmoveIndex: -1, |
|
scrollViewId: '', |
|
touchmoveTimeout: '', |
|
loaded: false |
|
} |
|
}, |
|
watch: { |
|
options: { |
|
handler: function() { |
|
this.setList() |
|
}, |
|
deep: true |
|
} |
|
}, |
|
mounted() { |
|
if (this.localdata.length || this.options.length) { |
|
setTimeout(() => { |
|
this.setList() |
|
}, 50) |
|
setTimeout(() => { |
|
this.loaded = true |
|
}, 300); |
|
} else if (this.collection) { |
|
if (!this.manual) { |
|
this._execLoadData((data) => { |
|
this.lists = this.groupData(data); |
|
}) |
|
} |
|
} |
|
}, |
|
methods: { |
|
groupData(data) { |
|
let groups = {}; |
|
for (let i = 0; i < data.length; i++) { |
|
let item = data[i]; |
|
let group = item.group; |
|
if (!groups[group]) { |
|
groups[group] = { |
|
"title": group, |
|
"value": group, |
|
"itemIndex": i, |
|
"items": [] |
|
} |
|
} |
|
groups[group].items.push(item); |
|
} |
|
let result = [] |
|
for (let g in groups) { |
|
let group = groups[g]; |
|
let items = group.items; |
|
for (let j = 0; j < items.length; j++) { |
|
items[j].itemIndex = j; |
|
} |
|
result.push(group); |
|
} |
|
return result; |
|
}, |
|
setList(data) { |
|
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['value'] = value.letter |
|
obj['text'] = item |
|
obj['itemIndex'] = index |
|
index++ |
|
obj.checked = item.checked ? item.checked : false |
|
return obj |
|
}) |
|
this.lists.push({ |
|
title: value.letter, |
|
value: 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 = 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 = 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 |
|
}, |
|
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; |
|
} |
|
|
|
.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> |