activityList.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. <template>
  2. <Theme>
  3. <view class="wrap" id="pageContainer">
  4. <Navbar border fixed autoBack title="免邮专区" @leftClick="leftClick">
  5. </Navbar>
  6. <view class="tops" id="tabs" :style="{ top: tabTop + 'px' }">
  7. <view class="tab">
  8. <Tab
  9. :active="actvieNum"
  10. keyName="name"
  11. isTran
  12. :tabList="tabList"
  13. @confirm="tabClick"
  14. />
  15. </view>
  16. </view>
  17. <view class="content">
  18. <List
  19. url="/shop/activity/list"
  20. :topHeight="tabHeight"
  21. :defaultParams="defaultParams"
  22. :pageSize="20"
  23. isLoading
  24. ref="listRef"
  25. @datas="getList"
  26. >
  27. <template #item="{ item, index }">
  28. <shopList
  29. channel="1"
  30. isFree="1"
  31. :item="item"
  32. @collect="collectClick($event, index)"
  33. />
  34. </template>
  35. </List>
  36. </view>
  37. </view>
  38. </Theme>
  39. </template>
  40. <script setup>
  41. import { ref, reactive, watch, onMounted, nextTick } from "vue";
  42. import Navbar from "@/components/navbar";
  43. import { t } from "@/locale";
  44. import { onLoad, onShow, onReachBottom, onPageScroll } from "@dcloudio/uni-app";
  45. import List from "@/components/list";
  46. import { query, systemInfo } from "@/utils";
  47. import shopList from "./components/shop_list";
  48. import Tab from "@/components/tabs";
  49. import { SHOP_USER_COLLECT, SHOP_GOODS_CATEGORY } from "@/api";
  50. const searchValue = ref("");
  51. const listRef = ref(null);
  52. const popupRef = ref(null);
  53. const actvieNum = ref(0);
  54. const tabHeight = ref(0);
  55. const tabTop = ref(44);
  56. const dataList = ref([]);
  57. const tabList = ref([]);
  58. const defaultParams = reactive({
  59. cid: 0,
  60. });
  61. // 防抖标记(防止重复触发)
  62. const isLoading = ref(false);
  63. // 自定义触发阈值:距离底部 200px 时触发
  64. const triggerThreshold = ref(200);
  65. // 页面总高度(用于计算距离底部距离)
  66. const pageTotalHeight = ref(0);
  67. // 列表加载完成后调用(需在列表组件的加载回调中执行)
  68. const handleLoadComplete = async () => {
  69. isLoading.value = false;
  70. const rect = await query("#pageContainer", this);
  71. pageTotalHeight.value = rect.height;
  72. };
  73. onMounted(() => {
  74. nextTick(async () => {
  75. const res = await query("#tabs", this);
  76. tabTop.value = res.top + systemInfo().statusBarHeight;
  77. tabHeight.value = res.height;
  78. const rect = await query("#pageContainer", this);
  79. pageTotalHeight.value = rect.height;
  80. nextTick(() => {
  81. listRef.value && listRef.value.getData();
  82. });
  83. });
  84. });
  85. onPageScroll((e) => {
  86. nextTick(() => {
  87. if (isLoading.value || !pageTotalHeight.value) return;
  88. const systemInfo = uni.getSystemInfoSync();
  89. const windowHeight = systemInfo.windowHeight;
  90. const scrollTop = e.scrollTop;
  91. // 计算距离底部的距离:总高度 - 滚动距离 - 可视高度
  92. const distanceToBottom = pageTotalHeight.value - scrollTop - windowHeight;
  93. if (distanceToBottom <= triggerThreshold.value) {
  94. isLoading.value = true;
  95. listRef.value && listRef.value.scrolltolower();
  96. }
  97. });
  98. });
  99. const rightClick = () => {
  100. popupRef.value && popupRef.value.open();
  101. };
  102. const getList = (list) => {
  103. dataList.value = list;
  104. handleLoadComplete();
  105. };
  106. const popClose = () => {
  107. popupRef.value && popupRef.value.close();
  108. };
  109. onLoad((options) => {});
  110. onShow(() => {
  111. getCategory();
  112. });
  113. const leftClick = () => {
  114. uni.navigateBack();
  115. };
  116. const getCategory = async () => {
  117. try {
  118. const res = await SHOP_GOODS_CATEGORY();
  119. tabList.value = res.data || [];
  120. } catch (error) {
  121. Toast(error.msg);
  122. }
  123. };
  124. const tabClick = (item, index) => {
  125. defaultParams.cid = item.id;
  126. if (actvieNum.value == index) return;
  127. actvieNum.value = index;
  128. nextTick(() => {
  129. listRef.value && listRef.value.handleRefresh();
  130. });
  131. };
  132. const collectClick = (item, index) => {
  133. setCollect(
  134. {
  135. channel: 1,
  136. type: "good",
  137. goods_id: item.num_iid,
  138. seller_id: item.seller_id,
  139. title: item.title,
  140. pic_url: item.pic_url,
  141. price: item.price,
  142. },
  143. index
  144. );
  145. };
  146. const setCollect = async (params, index) => {
  147. try {
  148. const res = await SHOP_USER_COLLECT(params);
  149. nextTick(() => {
  150. dataList.value[index].isCollect = res.data.collect;
  151. listRef.value && listRef.value.setList(dataList.value);
  152. });
  153. } catch (error) {
  154. Toast(error.msg);
  155. }
  156. };
  157. </script>
  158. <style lang="less" scoped>
  159. @import url("@/style.less");
  160. .wrap {
  161. min-height: 100vh;
  162. background-color: var(--bg);
  163. .nav_center {
  164. display: flex;
  165. width: calc(100% - 46px - 50px);
  166. .icon-camera {
  167. color: #adb8cc;
  168. font-size: 56rpx;
  169. }
  170. .img_left {
  171. position: relative;
  172. .del {
  173. position: absolute;
  174. right: -10rpx;
  175. top: -10rpx;
  176. }
  177. }
  178. }
  179. .nav_right {
  180. color: var(--black);
  181. .size(12px);
  182. font-weight: 700;
  183. }
  184. .tops {
  185. position: fixed;
  186. top: 44px;
  187. left: 0;
  188. right: 0;
  189. background-color: var(--bg);
  190. z-index: 1;
  191. .tab {
  192. padding: 0 24rpx;
  193. }
  194. }
  195. .content {
  196. padding: 120rpx 32rpx 16rpx;
  197. /deep/ .wrap_list {
  198. .uni-scroll-view-content {
  199. > uni-view {
  200. .flex();
  201. flex-wrap: wrap;
  202. gap: 16rpx;
  203. .u-list-item {
  204. width: calc((100% - 16rpx) / 2);
  205. }
  206. }
  207. }
  208. }
  209. }
  210. }
  211. .pop_cont {
  212. color: var(--text);
  213. .size(28rpx);
  214. line-height: 60rpx;
  215. }
  216. .pop_tip {
  217. color: var(--text-01);
  218. .size(28rpx);
  219. line-height: 60rpx;
  220. }
  221. .pop_btn {
  222. margin-top: 32rpx;
  223. height: 76rpx;
  224. padding: 16rpx 30rpx;
  225. color: var(--text-01);
  226. border: 1px solid var(--text-01);
  227. border-radius: 16rpx;
  228. .size(24rpx);
  229. .flex_center();
  230. }
  231. </style>