| <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" @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" | 
|                 :class="touchmoveIndex == key ? 'uni-indexed-list__menu--active' : ''"> | 
|                 <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 | 
|         }, | 
|         emits: ['click'], | 
|         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 lang="scss" 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; | 
|         /* #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 { | 
|         font-size: 12px; | 
|         text-align: center; | 
|         color: #aaa; | 
|     } | 
|   | 
|     .uni-indexed-list__menu--active { | 
|         // background-color: rgb(200, 200, 200); | 
|     } | 
|   | 
|     .uni-indexed-list__menu--active {} | 
|   | 
|     .uni-indexed-list__menu-text--active { | 
|         border-radius: 16px; | 
|         width: 16px; | 
|         height: 16px; | 
|         line-height: 16px; | 
|         background-color: #007aff; | 
|         color: #fff; | 
|     } | 
|   | 
|     .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> |