index.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. <template>
  2. <div class="collections-list">
  3. <PageBanner :title="route.params.name as string" :img="bgImg" />
  4. <VanList
  5. v-model:loading="loading"
  6. :finished="noMore"
  7. finished-text="no more"
  8. :immediate-check="false"
  9. @load="onLoad"
  10. >
  11. <Waterfall
  12. background-color="#f7f6f3"
  13. :list="list"
  14. :breakpoints="{
  15. 500: { rowPerView: 2 },
  16. }"
  17. :gutter="20"
  18. >
  19. <template #item="{ item, url }">
  20. <div
  21. class="collections-list-card"
  22. @click="
  23. $router.push({
  24. name: 'CollectionsDetail',
  25. query: { id: item.id },
  26. })
  27. "
  28. >
  29. <VanImage :src="url" width="100%" :height="item.imgHeight + 'px'" />
  30. <p class="limit-line line-2">{{ item.name }}</p>
  31. </div>
  32. </template>
  33. </Waterfall>
  34. </VanList>
  35. </div>
  36. </template>
  37. <script lang="ts" setup>
  38. import { computed, ref, watch } from "vue";
  39. import { Waterfall } from "vue-waterfall-plugin-next";
  40. import { getBaseURL } from "@dage/service";
  41. import { getCollectionListApi, type CollectionListItem } from "@/api";
  42. import PageBanner from "@/components/PageBanner.vue";
  43. import { PaginationType, usePagination } from "@/utils/usePagination";
  44. import { useCollectionStore } from "@/stores/collection";
  45. import "vue-waterfall-plugin-next/dist/style.css";
  46. import { useRoute } from "vue-router";
  47. import { NAV_LIST } from "../constants";
  48. const baseUrl = getBaseURL();
  49. const collectionStore = useCollectionStore();
  50. const route = useRoute();
  51. // 当前页图片数据是否全部加载完成
  52. const rendering = ref(false);
  53. const list = ref<any[]>([]);
  54. const realType = computed(
  55. () => NAV_LIST.find((i) => i.type === (route.params.name as string))?.name
  56. );
  57. const bgImg = computed(
  58. () =>
  59. baseUrl +
  60. collectionStore.thumbList.find((i) => i.type === realType.value)?.thumb
  61. );
  62. const {
  63. pageNum,
  64. list: sourceList,
  65. noMore: _noMore,
  66. loading: fetchLoading,
  67. getList,
  68. } = usePagination<CollectionListItem>(
  69. (params) => {
  70. rendering.value = true;
  71. return getCollectionListApi({
  72. type: realType.value,
  73. ...params,
  74. });
  75. },
  76. PaginationType.DEFAULT,
  77. 20
  78. );
  79. const loading = computed(() => rendering.value || fetchLoading.value);
  80. const noMore = computed(() => !loading.value && _noMore.value);
  81. const onLoad = () => {
  82. // 检查用户是否滚动到页面底部
  83. if (!loading.value && !noMore.value && !rendering.value) {
  84. pageNum.value++;
  85. getList();
  86. }
  87. };
  88. watch(
  89. route,
  90. () => {
  91. pageNum.value = 1;
  92. list.value = [];
  93. getList();
  94. },
  95. {
  96. immediate: true,
  97. }
  98. );
  99. const ITEM_WIDTH = window.innerWidth / 2 - 60;
  100. watch(sourceList, async (v) => {
  101. if (!v.length) return;
  102. rendering.value = true;
  103. try {
  104. for (const i of v) {
  105. const url = baseUrl + i.thumb;
  106. const ratio = await getImgRatio(url);
  107. list.value.push({
  108. ...i,
  109. imgHeight: ITEM_WIDTH * ratio,
  110. src: url,
  111. });
  112. }
  113. } finally {
  114. setTimeout(() => {
  115. rendering.value = false;
  116. }, 500);
  117. }
  118. });
  119. const getImgRatio: (url: string) => Promise<number> = (url: string) => {
  120. return new Promise((res) => {
  121. const img = new Image();
  122. img.src = url;
  123. img.onload = () => {
  124. const ratio = Math.round((img.height / img.width) * 100) / 100;
  125. res(ratio);
  126. };
  127. img.onerror = () => {
  128. res(0);
  129. };
  130. });
  131. };
  132. </script>
  133. <style lang="scss" scoped>
  134. @import "./index.scss";
  135. </style>