tm-quickIndex.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. <template>
  2. <view class="tm-quickIndex " :style="{
  3. height: activeHeight_watch + 'px'
  4. }">
  5. <view :style="{
  6. height: activeHeight_watch + 'px'
  7. }">
  8. <tm-loadding v-if="loadding" label="处理中..."></tm-loadding>
  9. <scroll-view scroll-y :class="[black_tmeme?'grey-darken-4':'white']" :style="{
  10. height: activeHeight_watch + 'px',
  11. }" @scroll="scrollIn" :scroll-into-view="guid+'_'+(isScroll?'':active_value)">
  12. <view v-for="(item,index) in dataList" :key="index" :id="guid+'_'+index" class="tm-quickIndex-item">
  13. <view :class="[black_tmeme?'grey-darken-5':'grey-lighten-4 text']" class=" text-size-s text-weight-b px-32 py-12">{{item.title}}</view>
  14. <view>
  15. <view v-for="(item2,index2) in item.children" :key="index2">
  16. <slot name="cell" :data="{prevent:index,children:index2,total:item.children.length,item:item2,title:item2[rangKey],color:color_tmeme,black:black_tmeme}">
  17. <view :class="[index2!==item.children.length-1?'border-grey-lighten-4-b-1 ':'',black_tmeme?'bk':'']" class="mx-32 py-24 flex-start" @click="changeIndex(index,index2,item2)">
  18. <view v-if="item2['icon']" style="width: 48rpx;height: 48rpx;" class="mr-24 rounded flex-center overflow">
  19. <tm-icons :size="48" :name="item2['icon']"></tm-icons>
  20. </view>
  21. <view class="text-size-n">
  22. {{item2[rangKey]}}
  23. </view>
  24. </view>
  25. </slot>
  26. </view>
  27. </view>
  28. </view>
  29. </scroll-view>
  30. </view>
  31. <view class="tm-quickIndex-index flex-center flex-col pr-16" :style="{
  32. height: activeHeight_watch + 'px'
  33. }">
  34. <view v-if="showtips"
  35. :class="[`text-${color_tmeme}`,black_tmeme?'bk':'']"
  36. class="tm-quickIndex-index-Tips absolute rounded shadow-10 flex-center white text-size-g text-weight-b">
  37. {{ returnIndexStr(scrollIndx) }}
  38. </view>
  39. <!-- <view v-if="scrollInBarIndex"
  40. :class="[`text-${color}`]"
  41. class="tm-quickIndex-index-Tips absolute rounded shadow-10 flex-center white text-size-g text-weight-b">
  42. {{returnIndexStr(scrollIndx)}} :class="[scrollIndx==index?`text-${color} text-weight-b`:'']"
  43. </view> -->
  44. <view v-if="activeHeight_watch>0" @touchend.stop.prevent="indexMove($event,'end')" @touchmove.stop.prevent="indexMove($event,'scroll')"
  45. class="tm-quickIndex-index-Bk round-24 shadow-3 " :class="[black_tmeme?'grey-darken-5 bk':'white']">
  46. <view @click.stop="acitveItemClick($event,index)"
  47. class="tm-quickIndex-index-item text-size-xxs flex-center px-2"
  48. v-for="(item,index) in dataList" :key="index">
  49. {{
  50. returnIndexStr(index)
  51. }}
  52. </view>
  53. </view>
  54. </view>
  55. </view>
  56. </template>
  57. <script>
  58. /**
  59. * 快速索引
  60. * @property {Array} list = [] 默认:[],列表数据,格式:[{title:"汽车品牌",children:[{title:"宝马"},{title:"奔驰"}]}]
  61. * @property {String} rang-key = [] 默认:'title',列表对象key,
  62. * @property {String | Number} height = [] 默认:0,高度,默认为0时,自动使用屏幕的高度。
  63. * @property {Number} value = [] 默认:0,当前滚动的索引位置,推荐使用v-model或者value.sync
  64. * @property {String} color = [] 默认:primary,主题色。
  65. * @property {Function} change 点击列表项时产生的事件,返回参数:{prent:父Index,children:子index,data:项数据。}
  66. * @example <tm-quickIndex :list='[{title:"汽车品牌",children:[{title:"宝马"},{title:"奔驰"}]}]'></tm-quickIndex>
  67. * 如果 不提供index索引字符将截取title第一个字符作为索引。如果title第一个没有将使用自建的数字索引。
  68. */
  69. import tmIcons from "@/tm-vuetify/components/tm-icons/tm-icons.vue"
  70. import tmLoadding from "@/tm-vuetify/components/tm-loadding/tm-loadding.vue"
  71. export default {
  72. components:{tmIcons,tmLoadding},
  73. name: 'tm-quickIndex',
  74. model: {
  75. prop: 'value',
  76. event: 'input'
  77. },
  78. props: {
  79. // 高度,默认为0时,自动使用屏幕的高度。
  80. height: {
  81. type: String | Number,
  82. default: 0
  83. },
  84. // 当前滚动的位置。
  85. value: {
  86. type: Number,
  87. default: 0
  88. },
  89. // 当前滚动的位置。
  90. color: {
  91. type: String,
  92. default: "primary"
  93. },
  94. list: {
  95. type: Array,
  96. default: () => {
  97. return [];
  98. }
  99. },
  100. rangKey: {
  101. type: String,
  102. default: "title"
  103. },
  104. black: {
  105. type: String|Boolean,
  106. default: null
  107. },
  108. // 跟随主题色的改变而改变。
  109. fllowTheme:{
  110. type:Boolean|String,
  111. default:true
  112. }
  113. },
  114. watch: {
  115. value: function() {
  116. this.active = this.value;
  117. this.isScroll=false;
  118. this.scrollIndx = this.value;
  119. },
  120. list:{
  121. deep:true,
  122. handler(){
  123. this.dataList = this.list;
  124. }
  125. }
  126. },
  127. computed: {
  128. black_tmeme: function() {
  129. if (this.black !== null) return this.black;
  130. return this.$tm.vx.state().tmVuetify.black;
  131. },
  132. color_tmeme:function(){
  133. if(this.$tm.vx.state().tmVuetify.color!==null&&this.$tm.vx.state().tmVuetify.color && this.fllowTheme){
  134. return this.$tm.vx.state().tmVuetify.color;
  135. }
  136. return this.color;
  137. },
  138. active: {
  139. get: function() {
  140. return this.active_value;
  141. },
  142. set: async function(val) {
  143. this.active_value = val;
  144. this.$emit('input', val);
  145. this.$emit('update:value', val);
  146. let t = this;
  147. this.showtips = true;
  148. let idx = 5655555
  149. clearTimeout(idx)
  150. idx = setTimeout(function(){
  151. t.showtips = false;
  152. },500)
  153. }
  154. },
  155. activeHeight_watch: {
  156. get: function() {
  157. return this.activeHeight;
  158. },
  159. set: function(val) {
  160. this.activeHeight = val;
  161. }
  162. }
  163. },
  164. data() {
  165. return {
  166. minTop:0,
  167. activeHeight: 0,
  168. guid: "",
  169. active_value: 0,
  170. listBound: [],
  171. nowIndex: 0,
  172. showtips: false,
  173. isScroll: true,
  174. quinkBar: null,
  175. scrollIndx: 0,
  176. scrollInBarIndex: false,
  177. dataList:[],
  178. loadding:true
  179. };
  180. },
  181. async mounted() {
  182. this.guid = uni.$tm.guid();
  183. let t = this;
  184. this.activeHeight_watch = uni.upx2px(this.height);
  185. this.loadding=true;
  186. await uni.$tm.sleep(50)
  187. this.dataList = [...this.list];
  188. this.$nextTick(async function() {
  189. if (!this.activeHeight_watch) {
  190. let sysinfo = uni.getSystemInfoSync();
  191. this.activeHeight_watch = sysinfo.windowHeight;
  192. }
  193. let df = await this.$Querey(".tm-quickIndex",this).catch(e=>{});
  194. this.minTop = df[0].top;
  195. let indexbar = await t.$Querey(".tm-quickIndex-index-Bk", t).catch(e => {})
  196. t.quinkBar = indexbar[0]
  197. await uni.$tm.sleep(100)
  198. t.active = t.value;
  199. uni.createSelectorQuery().in(t).selectAll('.tm-quickIndex-item')
  200. .boundingClientRect(res => {
  201. res.forEach(item => {
  202. t.listBound.push(item.top)
  203. })
  204. t.loadding=false;
  205. }).exec()
  206. });
  207. },
  208. methods: {
  209. returnIndexStr(index){
  210. let item = this.list[index];
  211. if(!item || typeof item === 'undefined') return;
  212. if(item['index']&& typeof item['index'] !=='undefined'){
  213. return item['index'];
  214. }else{
  215. if(item[this.rangKey][0]&& typeof item[this.rangKey][0] !=='undefined'){
  216. return item[this.rangKey][0];
  217. }
  218. }
  219. return index+1
  220. },
  221. scrollIn(e) {
  222. let t = this;
  223. let y = e.detail.scrollTop;
  224. this.isScroll = true;
  225. function chatIndex(min) {
  226. let index = 0;
  227. for (let i = 0; i < t.listBound.length; i++) {
  228. if (t.listBound[i] >= min + t.minTop+1) {
  229. index = i;
  230. break;
  231. }
  232. }
  233. return index;
  234. }
  235. this.nowIndex = chatIndex(y) - 1;
  236. },
  237. changeIndex(prentindex, childrenindex, item) {
  238. this.$emit('change', {
  239. prent: prentindex,
  240. children: childrenindex,
  241. data: item
  242. })
  243. },
  244. async acitveItemClick(e, indx) {
  245. this.isScroll = false;
  246. if (this.list.length <= 0) return;
  247. this.active = indx;
  248. },
  249. async indexMove(e, type) {
  250. let t = this;
  251. if (this.list.length <= 0) return;
  252. if (e.changedTouches.length > 1) return;
  253. let y = e.changedTouches[0].clientY;
  254. let itemHeight = uni.upx2px(40);
  255. let ClickTop = e.target.offsetTop;
  256. let index = 0;
  257. if (y <= this.quinkBar.top) {
  258. index = 0;
  259. } else if (y >= this.quinkBar.bottom) {
  260. index = this.list.length - 1;
  261. } else {
  262. let xy = y - this.quinkBar.top
  263. index = Math.floor(xy / itemHeight);
  264. }
  265. if(index>=this.list.length-1) index = this.list.length-1
  266. if(index<=0) index = 0;
  267. this.isScroll = false;
  268. if(this.scrollIndx!==index){
  269. this.scrollIndx = index
  270. }
  271. if(this.active!==index){
  272. this.active = index;
  273. }
  274. if (type == 'end') {
  275. t.scrollInBarIndex = false;
  276. } else {
  277. t.scrollInBarIndex = true;
  278. }
  279. }
  280. },
  281. };
  282. </script>
  283. <style lang="scss" scoped>
  284. .tm-quickIndex {
  285. position: relative;
  286. .tm-quickIndex-index {
  287. position: absolute;
  288. right: 0upx;
  289. top: 0;
  290. .tm-quickIndex-index-item {
  291. width: 40rpx;
  292. height: 40rpx;
  293. // background: rgba(255,255,255,0.1);
  294. }
  295. .tm-quickIndex-index-Tips {
  296. right: 160rpx;
  297. width: 100rpx;
  298. height: 100rpx;
  299. }
  300. }
  301. }
  302. </style>