indexed-list.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. <template>
  2. <view class="uni-indexed">
  3. <scroll-view :scroll-into-view="scrollViewId" :style="{ height: winHeight + 'px' }" class="uni-indexed__list" scroll-y>
  4. <block v-for="(list, idx) in lists" :key="idx">
  5. <view v-if="list.items && list.items.length > 0" :id="'uni-indexed-list-' + list.key" class="uni-indexed__list-title">{{ list.key }}</view>
  6. <view v-if="list.items && list.items.length > 0" class="uni-list">
  7. <view v-for="(item, index) in list.items" :key="index" class="uni-list-item" hover-class="uni-list-item--hover">
  8. <view class="uni-list-item__container" @click="onClick(idx, index)">
  9. <view v-if="showSelect" style="margin-right: 20upx;">
  10. <uni-icon :type="item.checked ? 'checkbox-filled' : 'circle'" :color="item.checked ? '#007aff' : '#aaa'" size="24" />
  11. </view>
  12. <view class="uni-list-item__content">{{ item.name }}</view>
  13. </view>
  14. </view>
  15. </view>
  16. </block>
  17. </scroll-view>
  18. <view :class="touchmove ? 'active' : ''" :style="{ height: winHeight + 'px' }" class="uni-indexed__menu" @touchstart="touchStart" @touchmove.stop.prevent="touchMove" @touchend="touchEnd">
  19. <text v-for="(list, key) in lists" :key="key" :class="touchmoveIndex == key ? 'active' : ''" :style="{ height: itemHeight + 'px', lineHeight: itemHeight + 'px' }" class="uni-indexed__menu-item">
  20. {{ list.key }}
  21. </text>
  22. </view>
  23. <view v-if="touchmove" class="uni-indexed--alert">{{ lists[touchmoveIndex].key }}</view>
  24. </view>
  25. </template>
  26. <script>
  27. import uniIcon from '../icon/icon.vue';
  28. export default {
  29. name: 'UniIndexedList',
  30. components: {
  31. uniIcon
  32. },
  33. props: {
  34. options: {
  35. type: Array,
  36. default () {
  37. return [];
  38. }
  39. },
  40. showSelect: {
  41. type: Boolean,
  42. default: false
  43. }
  44. },
  45. data() {
  46. return {
  47. lists: [],
  48. touchmove: false,
  49. touchmoveIndex: -1,
  50. itemHeight: 0,
  51. winHeight: 0,
  52. scrollViewId: ''
  53. };
  54. },
  55. created() {
  56. let winHeight = uni.getSystemInfoSync().windowHeight;
  57. this.itemHeight = winHeight / this.options.length;
  58. this.winHeight = winHeight;
  59. // if (!this.showSelect) {
  60. // this.lists = this.options;
  61. // return;
  62. // }
  63. // console.log(this.options)
  64. this.lists = this.options.map(value => {
  65. // console.log(value)
  66. let items = value.data.map(item => {
  67. let obj = {};
  68. // for (let key in item) {
  69. obj['key'] = value.letter;
  70. obj['name'] = item
  71. // }
  72. obj.checked = item.checked ? item.checked : false;
  73. return obj;
  74. });
  75. return {
  76. title: value.letter,
  77. key: value.letter,
  78. items: items
  79. };
  80. });
  81. // console.log(this.lists)
  82. },
  83. methods: {
  84. touchStart(e) {
  85. this.touchmove = true;
  86. let pageY = e.touches[0].pageY;
  87. let index = Math.floor(pageY / this.itemHeight);
  88. let item = this.lists[index];
  89. if (item) {
  90. this.scrollViewId = 'uni-indexed-list-' + item.key;
  91. this.touchmoveIndex = index;
  92. }
  93. },
  94. touchMove(e) {
  95. let pageY = e.touches[0].pageY;
  96. let index = Math.floor(pageY / this.itemHeight);
  97. let item = this.lists[index];
  98. if (item) {
  99. this.scrollViewId = 'uni-indexed-list-' + item.key;
  100. this.touchmoveIndex = index;
  101. }
  102. },
  103. touchEnd() {
  104. this.touchmove = false;
  105. this.touchmoveIndex = -1;
  106. },
  107. onClick(idx, index) {
  108. let obj = {};
  109. for (let key in this.lists[idx].items[index]) {
  110. obj[key] = this.lists[idx].items[index][key];
  111. }
  112. let select = [];
  113. if (this.showSelect) {
  114. this.lists[idx].items[index].checked = !this.lists[idx].items[index].checked;
  115. this.lists.forEach((value, idx) => {
  116. value.items.forEach((item, index) => {
  117. if (item.checked) {
  118. let obj = {};
  119. for (let key in this.lists[idx].items[index]) {
  120. obj[key] = this.lists[idx].items[index][key];
  121. }
  122. select.push(obj);
  123. }
  124. });
  125. });
  126. }
  127. this.$emit('click', {
  128. item: obj,
  129. select: select
  130. });
  131. }
  132. }
  133. };
  134. </script>
  135. <style>
  136. @charset "UTF-8";
  137. .uni-list {
  138. background-color: #fff;
  139. position: relative;
  140. width: 100%;
  141. display: flex;
  142. flex-direction: column
  143. }
  144. .uni-list::after {
  145. position: absolute;
  146. z-index: 10;
  147. right: 0;
  148. bottom: 0;
  149. left: 0;
  150. height: 1px;
  151. content: '';
  152. -webkit-transform: scaleY(.5);
  153. transform: scaleY(.5);
  154. background-color: #c8c7cc
  155. }
  156. .uni-list::before {
  157. position: absolute;
  158. z-index: 10;
  159. right: 0;
  160. top: 0;
  161. left: 0;
  162. height: 1px;
  163. content: '';
  164. -webkit-transform: scaleY(.5);
  165. transform: scaleY(.5);
  166. background-color: #c8c7cc
  167. }
  168. .uni-list-item {
  169. font-size: 32upx;
  170. position: relative;
  171. display: flex;
  172. flex-direction: column;
  173. justify-content: space-between;
  174. align-items: center
  175. }
  176. .uni-list-item__container {
  177. padding: 24upx 30upx;
  178. width: 100%;
  179. box-sizing: border-box;
  180. flex: 1;
  181. position: relative;
  182. display: flex;
  183. flex-direction: row;
  184. justify-content: space-between;
  185. align-items: center
  186. }
  187. .uni-list-item__container:after {
  188. position: absolute;
  189. z-index: 3;
  190. right: 0;
  191. bottom: 0;
  192. left: 30upx;
  193. height: 1px;
  194. content: '';
  195. -webkit-transform: scaleY(.5);
  196. transform: scaleY(.5);
  197. background-color: #c8c7cc
  198. }
  199. .uni-indexed {
  200. display: flex;
  201. flex-direction: row
  202. }
  203. .uni-indexed__list {
  204. flex: 1;
  205. height: 100vh
  206. }
  207. .uni-indexed__list-title {
  208. padding: 10upx 24upx;
  209. line-height: 1.5;
  210. background-color: #f7f7f7;
  211. font-size: 24upx
  212. }
  213. .uni-indexed__menu {
  214. width: 46upx;
  215. height: 100vh;
  216. background-color: #d3d3d3;
  217. display: flex;
  218. flex-direction: column
  219. }
  220. .uni-indexed__menu.active {
  221. background-color: #c8c8c8
  222. }
  223. .uni-indexed__menu.active .uni-indexed__menu-item {
  224. color: #333
  225. }
  226. .uni-indexed__menu.active .uni-indexed__menu-item.active {
  227. color: #007aff
  228. }
  229. .uni-indexed__menu-item {
  230. color: #aaa;
  231. font-size: 22upx;
  232. text-align: center
  233. }
  234. .uni-indexed--alert {
  235. position: absolute;
  236. display: inline-flex;
  237. align-items: center;
  238. justify-content: center;
  239. z-index: 20;
  240. width: 160upx;
  241. height: 160upx;
  242. left: 50%;
  243. top: 50%;
  244. margin-left: -80upx;
  245. margin-top: -80upx;
  246. border-radius: 80upx;
  247. text-align: center;
  248. font-size: 70upx;
  249. color: #fff;
  250. background-color: rgba(0, 0, 0, .5)
  251. }
  252. </style>