123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- <template>
- <div class="collections">
- <img
- class="collections-banner"
- tabindex="0"
- aria-description="You've reached the banner area of the Collections section; this section has one image; please use the tab key to go through the content."
- :src="bannerUrl"
- />
- <div class="container">
- <Breadcrumb
- :parents="[
- {
- label: 'Collections',
- routeParams: {
- name: 'Collections',
- params: { type: NAV_LIST[0].type },
- },
- },
- ]"
- :cur-route="curRoute"
- />
- <div class="collections-main">
- <Menu />
- <div
- v-loading="loading"
- element-loading-background="rgba(122, 122, 122, 0.8)"
- class="collections-main__right"
- >
- <Waterfall :list="list" :gutter="30" :hasAroundGutter="false">
- <template #item="{ item, url }">
- <div
- class="collections-item"
- aria-label="Link"
- @click="handleItemClick(item)"
- >
- <img
- alt=""
- :src="url"
- aria-label="Image link"
- :style="{ height: item.imgHeight + 'px' }"
- />
- <div class="collections-item__inner">
- <p tabindex="0" :aria-description="item.name">
- {{ item.name }}
- </p>
- <p tabindex="0" :aria-description="item.digest">
- {{ item.digest }}
- </p>
- </div>
- </div>
- </template>
- </Waterfall>
- <p v-if="noData" class="no-more">no more</p>
- <div v-if="rendering && pageNum > 1" style="text-align: center">
- <VanLoading color="var(--van-primary-color)" />
- </div>
- </div>
- </div>
- </div>
- </div>
- <DetailDialog v-model:visible="visible" :id="checkedItemId" />
- </template>
- <script lang="ts" setup>
- import { Waterfall } from "vue-waterfall-plugin-next";
- import { useRoute } from "vue-router";
- import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue";
- import { getBaseURL } from "@dage/service";
- import { useBaseStore } from "@/stores/base";
- import Breadcrumb from "@/components/Breadcrumb/index.vue";
- import { getCollectionListApi, type CollectionListItem } from "@/api";
- import Menu from "./components/Menu.vue";
- import DetailDialog from "./components/DetailDialog/index.vue";
- import { NAV_LIST } from "./constants";
- import "vue-waterfall-plugin-next/dist/style.css";
- import { PaginationType, usePagination } from "@/utils/usePagination";
- const baseUrl = getBaseURL();
- const baseStore = useBaseStore();
- const bannerUrl = computed(() => {
- return (
- baseUrl +
- baseStore.bannerList.find((i) => i.name === "Collections")?.thumbPc
- );
- });
- const route = useRoute();
- const curRoute = computed(() =>
- NAV_LIST.find((i) => i.type === (route.params.type as string))
- );
- const visible = ref(false);
- const checkedItemId = ref<number | null>(null);
- // 当前页图片数据是否全部加载完成
- const rendering = ref(false);
- const list = ref<any[]>([]);
- const loading = computed(
- () => (rendering.value || fetchLoading.value) && pageNum.value === 1
- );
- const {
- pageNum,
- list: sourceList,
- noData,
- noMore,
- loading: fetchLoading,
- resetParams,
- getList,
- } = usePagination<CollectionListItem>(
- (params) => {
- return getCollectionListApi({
- type: curRoute.value?.name,
- ...params,
- });
- },
- PaginationType.DEFAULT,
- 20
- );
- const handleItemClick = (item: any) => {
- checkedItemId.value = item.id;
- visible.value = true;
- };
- const getImgRatio: (url: string) => Promise<number> = (url: string) => {
- return new Promise((res) => {
- const img = new Image();
- img.src = url;
- img.onload = () => {
- const ratio = Math.round((img.height / img.width) * 100) / 100;
- res(ratio);
- };
- img.onerror = () => {
- res(0);
- };
- });
- };
- const handleScroll = () => {
- // 检查用户是否滚动到页面底部
- if (
- window.innerHeight + window.scrollY >= document.body.offsetHeight &&
- !rendering.value &&
- !loading.value &&
- !noMore.value
- ) {
- console.log("Scrolled to bottom");
- pageNum.value += 1;
- getList();
- }
- };
- onMounted(() => {
- window.addEventListener("scroll", handleScroll);
- });
- onBeforeUnmount(() => {
- window.removeEventListener("scroll", handleScroll);
- });
- watch(sourceList, async (v) => {
- if (!v.length) return;
- rendering.value = true;
- try {
- for (const i of v) {
- const url = baseUrl + i.thumb;
- const ratio = await getImgRatio(url);
- list.value.push({
- ...i,
- imgHeight: 303 * ratio,
- src: url,
- });
- }
- } finally {
- rendering.value = false;
- }
- });
- watch(
- route,
- () => {
- if (route.name !== "Collections") return;
- list.value = [];
- resetParams();
- getList();
- },
- {
- immediate: true,
- }
- );
- </script>
- <style lang="scss" scoped>
- @import "./index.scss";
- </style>
|