index-list.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. <template>
  2. <view class="container">
  3. <view class="indexPosition">
  4. <view :class="[currentKey==item.name?'activeKey on':'activeKey']" v-for="(item,index) in keyList" @click="activeKeyHandle(item.name)">{{item.name}}
  5. </view>
  6. </view>
  7. <view v-if="ifShowKeyTip" :animation="animationData" class="pop">{{tipText}}</view>
  8. <scroll-view scroll-y="true" class="scroll-Y" :scroll-top="top" scroll-with-animation="true" @scroll="scroll">
  9. <view :class="[`box ${item.letter}`]" v-for="item in options">
  10. <view class="letter">{{item.letter}}</view>
  11. <view class="listWrap">
  12. <view class="list" v-for="val in item.data" @click="listClickHandle(val)">
  13. <view :class="[isSelectAll||checkedListIds.includes(val.id)?'iconWrap':'iconWrap on']">
  14. <image v-if="isSelectAll||checkedListIds.includes(val.id)" class="checkedIcon"
  15. src="../../static/check-checkbox.png" mode=""></image>
  16. </view>
  17. <text class="mainText">{{val.main}}</text>
  18. <text class="subText">{{val.sub}}</text>
  19. </view>
  20. </view>
  21. </view>
  22. </scroll-view>
  23. </view>
  24. </template>
  25. <script>
  26. export default {
  27. name: "index-list",
  28. props: {
  29. checkedResponsibleList: Array,
  30. options: Array,
  31. },
  32. data() {
  33. return {
  34. checkedList: [],
  35. checkedListIds: [],
  36. isSelectAll: false,
  37. keyList: [],
  38. top:0,
  39. scrollTop:0,
  40. currentKey:'',
  41. animationData:{},
  42. tipText:'',
  43. ifShowKeyTip:false
  44. };
  45. },
  46. computed: {
  47. },
  48. watch: {
  49. checkedResponsibleList: function(newVal, oldVal) {
  50. // console.log({newVal,oldVal});
  51. if (newVal.length != oldVal.length) {
  52. this.checkedListIds = JSON.parse(JSON.stringify(newVal)).map(item => item.id);
  53. this.checkedList = JSON.parse(JSON.stringify(newVal));
  54. this.$emit("listClick", this.checkedList);
  55. }
  56. },
  57. options:function(){
  58. this.initKeyIndex();
  59. this.top=0;
  60. // this.checkedList=[];
  61. // this.checkedListIds = JSON.parse(JSON.stringify(this.checkedResponsibleList)).map(item => item.id);
  62. // this.checkedList = JSON.parse(JSON.stringify(this.checkedResponsibleList));
  63. },
  64. },
  65. mounted() {
  66. this.checkedListIds = JSON.parse(JSON.stringify(this.checkedResponsibleList)).map(item => item.id);
  67. this.checkedList = JSON.parse(JSON.stringify(this.checkedResponsibleList));
  68. this.initKeyIndex();
  69. },
  70. methods: {
  71. showKeyTip(){
  72. var animation = uni.createAnimation({
  73. duration: 1000,
  74. timingFunction: 'ease',
  75. })
  76. this.animation = animation
  77. animation.opacity(1).step();
  78. this.animationData = animation.export();
  79. },
  80. initKeyIndex(){
  81. this.keyList = [];
  82. this.currentKey='';
  83. this.options.map(item=>{
  84. // console.log('item.letter',item.letter);
  85. if(!item.letter)return null;
  86. this.getDescBox(`.${item.letter}`).then(res=>{
  87. // console.log(res);
  88. this.keyList.push({
  89. name:item.letter,
  90. num:res
  91. });
  92. })
  93. });
  94. },
  95. scroll(event){
  96. const {scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY} = event.detail;
  97. this.scrollTop = scrollTop;
  98. // console.log(this.keyList);
  99. const tempArr = this.keyList.filter(item=>scrollTop>=item.num-90);
  100. const needArr = tempArr.pop();
  101. // console.log({tempArr});
  102. this.currentKey = needArr?needArr.name:'';
  103. },
  104. activeKeyHandle(key) {
  105. this.ifShowKeyTip=true;
  106. this.tipText = key.toUpperCase();
  107. this.getDescBox(`.${key.toLowerCase()}`).then(res=>{
  108. // console.log({res});
  109. // console.log(`.${key.toLowerCase()}`);
  110. if(!res||Math.abs(res)-90<=0||res == this.top-90)return;
  111. this.top = Math.abs(res+this.scrollTop-90);
  112. });
  113. this.showKeyTip();
  114. setTimeout(()=>this.ifShowKeyTip = false,1000);
  115. },
  116. // 获取元素距离顶部的高度
  117. getDescBox(className) {
  118. let that = this;
  119. let count = 0;
  120. return new Promise(resolve => {
  121. getHeight();
  122. function getHeight() {
  123. uni
  124. .createSelectorQuery()
  125. .in(that)
  126. .select(className)
  127. .boundingClientRect()
  128. .exec(res => {
  129. if (res[0]) {
  130. resolve(res[0].top);
  131. } else {
  132. that.$nextTick(() => {
  133. ++count <= 8 ? getHeight() : resolve(null);
  134. });
  135. }
  136. });
  137. }
  138. });
  139. },
  140. listClickHandle(val) {
  141. const tempIdsArr = JSON.parse(JSON.stringify(this.checkedListIds));
  142. const tempArr = JSON.parse(JSON.stringify(this.checkedList));
  143. const data = JSON.parse(JSON.stringify(val));
  144. // console.log({tempIdsArr,tempArr});
  145. // console.log(tempIdsArr.includes(data.id));
  146. if (tempIdsArr.includes(data.id)) {
  147. this.isSelectAll = false;
  148. tempIdsArr.splice(tempIdsArr.indexOf(data.id), 1);
  149. this.checkedList = tempArr.filter(item => item.id != data.id);
  150. this.checkedListIds = tempIdsArr;
  151. } else {
  152. this.checkedList.push(data);
  153. this.checkedListIds.push(data.id);
  154. // console.log(this.checkedListIds);
  155. }
  156. this.$emit("listClick", this.checkedList);
  157. }
  158. }
  159. }
  160. </script>
  161. <style lang="less">
  162. .container {
  163. position: relative;
  164. z-index: 1;
  165. height: 100%;
  166. overflow: scroll;
  167. .indexPosition {
  168. display: flex;
  169. flex-direction: column;
  170. justify-content: center;
  171. align-items: center;
  172. position: absolute;
  173. z-index: 10;
  174. right: 12.5rpx;
  175. width: 50rpx;
  176. height: 100%;
  177. .activeKey {
  178. display: flex;
  179. justify-content: center;
  180. align-items: center;
  181. flex: 1;
  182. width: 100%;
  183. font-size: 17.5rpx;
  184. font-family: SourceHanSansCN-Normal, SourceHanSansCN;
  185. font-weight: 400;
  186. color: #7B8599;
  187. &.on {
  188. color: #3377FF;
  189. }
  190. }
  191. }
  192. .pop {
  193. position: fixed;
  194. z-index: 100;
  195. left:50%;
  196. top:50%;
  197. width: 125rpx;
  198. height: 125rpx;
  199. margin-left: -62.5rpx;
  200. margin-top: -62.5rpx;
  201. text-align: center;
  202. line-height:125rpx;
  203. font-size: 35rpx;
  204. color: #FFFFFF;
  205. border-radius: 50%;
  206. background: rgba(0,0,0,0.6);
  207. }
  208. .scroll-Y {
  209. height: 100%;
  210. .box {
  211. .letter {
  212. height: 62.5rpx;
  213. line-height: 62.5rpx;
  214. font-size: 22.5rpx;
  215. font-family: SourceHanSansCN-Normal, SourceHanSansCN;
  216. font-weight: 400;
  217. color: #666F80;
  218. padding: 0 25rpx;
  219. }
  220. .listWrap {
  221. background-color: #FFFFFF;
  222. .list {
  223. position: relative;
  224. display: flex;
  225. flex-direction: row;
  226. justify-content: flex-start;
  227. align-items: center;
  228. height: 87.5rpx;
  229. padding: 0 25rpx;
  230. .iconWrap {
  231. width: 25rpx;
  232. height: 25rpx;
  233. margin-right: 25rpx;
  234. .checkedIcon {
  235. width: 25rpx;
  236. height: 25rpx;
  237. }
  238. &.on {
  239. border-radius: 50%;
  240. border: 2.5rpx solid #C3CAD9;
  241. }
  242. }
  243. .mainText {
  244. display: inline-block;
  245. font-size: 22.5rpx;
  246. font-family: SourceHanSansCN-Normal, SourceHanSansCN;
  247. font-weight: 400;
  248. color: #292C33;
  249. margin-right: 50rpx;
  250. }
  251. .subText {
  252. font-size: 22.5rpx;
  253. font-family: SourceHanSansCN-Normal, SourceHanSansCN;
  254. font-weight: 400;
  255. color: #7A8499;
  256. }
  257. &::after {
  258. position: absolute;
  259. right: 0;
  260. bottom: 0;
  261. display: block;
  262. content: '';
  263. width: 90%;
  264. border-bottom: 1px solid #DADEE6;
  265. }
  266. &:last-child {
  267. &::after {
  268. display: none;
  269. }
  270. }
  271. }
  272. }
  273. }
  274. }
  275. }
  276. </style>