cate.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. <template>
  2. <view class="category">
  3. <view class="category-wrapper" v-if="catrgoryList.length>0">
  4. <!-- 左边导航 -->
  5. <scroll-view scroll-y="true" class="left-wrapper" scroll-with-animation="true" :scroll-top="left_scroll">
  6. <view class="left-content">
  7. <view class="title-content" :class="select_index === index?'onSelected':''" v-for="(title,index) in catrgoryList"
  8. :key="title.id" @tap="choose(index)">{{title.name}}</view>
  9. </view>
  10. </scroll-view>
  11. <!-- 右边内容 -->
  12. <scroll-view scroll-y="true" class="right-wrapper" scroll-with-animation="true" :scroll-top="right_scroll" @scroll="myscroll">
  13. <view class="right-content">
  14. <!-- banner区域 -->
  15. <view class="banner-wrapper">
  16. <swiper class="swiper-content" :autoplay="true" :interval="3000" :circular="true">
  17. <swiper-item class="swiper-item" v-for="imgs in swiperList" :key="imgs.id">
  18. <image class="swiper-img" :src="imgs.src"></image>
  19. </swiper-item>
  20. </swiper>
  21. </view>
  22. <!-- 产品区 -->
  23. <view class="product-wrapper">
  24. <view class="category-item" :id="'list'+c_index" v-for="(c_item,c_index) in catrgoryList" :key="c_item.id">
  25. <view class="category-title">{{c_item.name}}</view>
  26. <view class="category-content">
  27. <view class="product-item" v-for="(p_item,p_index) in c_item.content" :key="p_item.id">
  28. <image class="product-img" :src="p_item.thumb"></image>
  29. <text class="product-title">{{p_item.cname}}</text>
  30. </view>
  31. </view>
  32. </view>
  33. </view>
  34. </view>
  35. </scroll-view>
  36. </view>
  37. </view>
  38. </template>
  39. <script>
  40. export default {
  41. data() {
  42. return {
  43. windows_height: 0, //屏幕高度
  44. swiperList: [],
  45. catrgoryList: [],
  46. select_index: 0,
  47. right_height: [], //右侧每个内容的高度集合
  48. right_scroll: 0, //右侧的滑动值
  49. left_height: 0, //左侧总高度
  50. left_scroll: 0, //左侧滑动值
  51. last: 0,
  52. }
  53. },
  54. onLoad() {
  55. this.init();
  56. this.windows_height = uni.getSystemInfoSync().windowHeight;
  57. },
  58. methods: {
  59. init() {
  60. uni.request({
  61. url: 'https://www.easy-mock.com/mock/5d351e87b5e1f213739d6498/shop/categoryList', //仅为示例,并非真实接口地址。
  62. method: 'GET',
  63. success: (res) => {
  64. if (res.data.error === 0) {
  65. this.catrgoryList = res.data.data.list;
  66. this.swiperList = res.data.data.banner;
  67. this.$nextTick(() => {
  68. this.getHeightList();
  69. })
  70. }
  71. }
  72. });
  73. },
  74. getHeightList() {
  75. let _this = this;
  76. let selectorQuery = uni.createSelectorQuery();
  77. selectorQuery.select('.left-content').boundingClientRect(function(rects) {
  78. _this.left_height = rects.height;
  79. });
  80. selectorQuery.selectAll('.category-item').boundingClientRect(function(rects) {
  81. _this.right_height = rects.map((item) => item.top);
  82. console.log(_this.right_height)
  83. }).exec();
  84. },
  85. choose(index) {
  86. if (this.select_index === index) {
  87. return;
  88. }
  89. this.select_index = index;
  90. // 加入防抖
  91. if (this.timeout) {
  92. clearTimeout(this.timeout); //清除计时器
  93. }
  94. this.timeout = setTimeout(() => {
  95. this.right_scroll = this.right_height[index] - 110;
  96. }, 300)
  97. },
  98. myscroll(e) {
  99. //引入节流
  100. let right_content_height = e.detail.scrollHeight - this.windows_height;
  101. if (right_content_height == e.detail.scrollTop) {
  102. return;
  103. }
  104. let scroll_top = e.detail.scrollTop + 110; //110是banner图的高度
  105. //判断当前的scrollTop在哪个区间内;
  106. let now = +new Date();
  107. if (now - this.last > 100) {
  108. this.last = now;
  109. let active_index = this.right_height.findIndex((value, index, arr) => value <= scroll_top && scroll_top < arr[index + 1]);
  110. this.select_index = active_index;
  111. if (this.left_height - this.windows_height) {
  112. //如果有超出部分
  113. let diff = this.left_height - this.windows_height
  114. this.left_scroll = Math.round((active_index * diff) / (this.catrgoryList.length - 1))
  115. }
  116. }
  117. }
  118. }
  119. }
  120. </script>
  121. <style lang="less">
  122. .category {
  123. .category-wrapper {
  124. width: 100%;
  125. display: flex;
  126. flex-direction: row;
  127. position: absolute;
  128. top: 0;
  129. bottom: 0;
  130. .left-wrapper {
  131. width: 200rpx;
  132. flex: 0 0 200rpx;
  133. background-color: #f6f6f6;
  134. .left-content {
  135. .title-content {
  136. width: 100%;
  137. height: 100rpx;
  138. display: flex;
  139. justify-content: center;
  140. align-items: center;
  141. font-size: 25rpx;
  142. border-bottom: 1px solid #dedede;
  143. cursor: pointer;
  144. &:last-child {
  145. border-bottom: 0;
  146. }
  147. &.onSelected {
  148. background-color: #fff;
  149. position: relative;
  150. color: #feb436;
  151. &::before {
  152. content: '';
  153. position: absolute;
  154. left: 0;
  155. top: 0;
  156. width: 10rpx;
  157. height: 100%;
  158. background: linear-gradient(124deg, #feb436 0%, #fb7c22 100%);
  159. }
  160. }
  161. }
  162. }
  163. }
  164. .right-wrapper {
  165. flex: 1;
  166. .right-content {
  167. width: 100%;
  168. padding: 20rpx 0;
  169. border-left: 1rpx solid #efefef;
  170. box-sizing: border-box;
  171. .banner-wrapper {
  172. padding: 0 20rpx;
  173. .swiper-content {
  174. width: 100%;
  175. height: 180rpx;
  176. margin-bottom: 20rpx;
  177. .swiper-item {
  178. .swiper-img {
  179. width: 100%;
  180. height: 180rpx;
  181. }
  182. }
  183. }
  184. }
  185. .product-wrapper {
  186. .category-item {
  187. .category-title {
  188. height: 60rpx;
  189. font-size: 26rpx;
  190. line-height: 60rpx;
  191. font-weight: 500;
  192. background-color: #f6f6f6;
  193. padding-left: 20rpx;
  194. color: #000;
  195. }
  196. .category-content {
  197. display: flex;
  198. flex-direction: row;
  199. flex-flow: wrap;
  200. padding: 20rpx 20rpx 0;
  201. .product-item {
  202. width: 33%;
  203. display: flex;
  204. flex-direction: column;
  205. justify-content: center;
  206. align-items: center;
  207. margin-bottom: 20rpx;
  208. .product-img {
  209. width: 120rpx;
  210. height: 140rpx;
  211. margin-bottom: 10rpx;
  212. }
  213. .product-title {
  214. font-size: 23rpx;
  215. }
  216. }
  217. }
  218. }
  219. }
  220. }
  221. }
  222. }
  223. }
  224. </style>